Pārlūkot izejas kodu

重新梳理视频播放器

yangchong 5 gadi atpakaļ
vecāks
revīzija
056462b303

+ 2 - 1
README.md

@@ -235,7 +235,8 @@
     - 06.在列表中播放
     - 07.在activity播放视频处理home键逻辑
     - 08.在fragment中播放
-    - 09.显示视频top[分享,下载,更多按钮控件]
+    - 09.1 显示正常视频top[分享,下载,更多按钮控件,默认不显示]
+    - 09.2 显示横屏视频top[tv投影,切换音频控件,默认显示]
     - 10.全局悬浮播放视频
     - 11.常见api说明
 - [视频优化处理](https://github.com/yangchong211/YCVideoPlayer/blob/master/read/wiki2.md)

+ 1 - 0
YCVideoPlayerLib/build.gradle

@@ -24,6 +24,7 @@ android {
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
     implementation 'com.android.support:appcompat-v7:28.0.0'
+    implementation 'com.android.support:cardview-v7:28.0.0'
     //这两个是必须要加的,其它的可供选择
     implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
     implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'

+ 11 - 7
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/controller/VideoPlayerController.java

@@ -54,6 +54,7 @@ import org.yczbj.ycvideoplayerlib.inter.listener.OnCompletedListener;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnPlayOrPauseListener;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnVideoBackListener;
 import org.yczbj.ycvideoplayerlib.inter.listener.OnVideoControlListener;
+import org.yczbj.ycvideoplayerlib.view.BaseToast;
 
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -225,7 +226,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
                 IntentFilter filter = new IntentFilter();
                 filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
                 mContext.registerReceiver(netChangedReceiver, filter);
-                VideoLogUtil.i("注册网络监听广播");
+                VideoLogUtil.i("广播监听---------注册网络监听广播");
             }
             hasRegisterNetReceiver = true;
         }
@@ -239,7 +240,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
         if (hasRegisterNetReceiver) {
             if (netChangedReceiver != null) {
                 mContext.unregisterReceiver(netChangedReceiver);
-                VideoLogUtil.i("解绑注册网络监听广播");
+                VideoLogUtil.i("广播监听---------解绑注册网络监听广播");
             }
             hasRegisterNetReceiver = false;
         }
@@ -254,7 +255,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
             mContext.registerReceiver(mBatterReceiver, new IntentFilter(
                     Intent.ACTION_BATTERY_CHANGED));
             hasRegisterBatteryReceiver = true;
-            VideoLogUtil.i("注册电池监听广播");
+            VideoLogUtil.i("广播监听---------注册电池监听广播");
         }
     }
 
@@ -266,7 +267,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
         if (hasRegisterBatteryReceiver) {
             mContext.unregisterReceiver(mBatterReceiver);
             hasRegisterBatteryReceiver = false;
-            VideoLogUtil.i("解绑电池监听广播");
+            VideoLogUtil.i("广播监听---------解绑电池监听广播");
         }
     }
 
@@ -777,6 +778,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
                 //隐藏电量图标
                 mBattery.setVisibility(GONE);
                 setTopVisibility(mIsTopLayoutVisibility);
+                VideoLogUtil.d("播放模式--------普通模式");
                 break;
             //全屏模式
             case ConstantKeys.PlayMode.MODE_FULL_SCREEN:
@@ -795,6 +797,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
                 if (mOnPlayerTypeListener!=null){
                     mOnPlayerTypeListener.onFullScreen();
                 }
+                VideoLogUtil.d("播放模式--------全屏模式");
                 break;
             //小窗口模式
             case ConstantKeys.PlayMode.MODE_TINY_WINDOW:
@@ -807,6 +810,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
                 if (mOnPlayerTypeListener!=null){
                     mOnPlayerTypeListener.onTinyWindow();
                 }
+                VideoLogUtil.d("播放模式--------小窗口模式");
                 break;
             default:
                 break;
@@ -893,7 +897,7 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
                     }
                 }
             }else {
-                Toast.makeText(mContext,"请检测是否有网络",Toast.LENGTH_SHORT).show();
+                BaseToast.showRoundRectToast("请检测是否有网络");
             }
         } else if (v == mFullScreen) {
             //全屏模式,重置锁屏,设置为未选中状态
@@ -919,14 +923,14 @@ public class VideoPlayerController extends AbsVideoPlayerController implements V
                 //开始从此位置播放
                 mVideoPlayer.restart();
             }else {
-                Toast.makeText(mContext,"请检测是否有网络",Toast.LENGTH_SHORT).show();
+                BaseToast.showRoundRectToast("请检测是否有网络");
             }
         } else if (v == mReplay) {
             //重新播放
             if(VideoPlayerUtils.isConnected(mContext)){
                 mRetry.performClick();
             }else {
-                Toast.makeText(mContext,"请检测是否有网络",Toast.LENGTH_SHORT).show();
+                BaseToast.showRoundRectToast("请检测是否有网络");
             }
         } else if (v == mShare) {
             //分享

+ 38 - 30
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/player/VideoPlayer.java

@@ -40,6 +40,7 @@ import org.yczbj.ycvideoplayerlib.inter.player.InterVideoPlayer;
 import org.yczbj.ycvideoplayerlib.manager.VideoPlayerManager;
 import org.yczbj.ycvideoplayerlib.utils.VideoLogUtil;
 import org.yczbj.ycvideoplayerlib.utils.VideoPlayerUtils;
+import org.yczbj.ycvideoplayerlib.view.BaseToast;
 import org.yczbj.ycvideoplayerlib.view.VideoTextureView;
 import java.io.IOException;
 import java.util.Map;
@@ -91,6 +92,9 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     private String mUrl;
     private Map<String, String> mHeaders;
     private int mBufferPercentage;
+    /**
+     * 是否从上一次位置播放,默认是true
+     */
     private boolean continueFromLastPosition = true;
     private long skipToPosition;
 
@@ -112,6 +116,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      * 初始化
      */
     private void init() {
+        BaseToast.init(mContext.getApplicationContext());
         mContainer = new FrameLayout(mContext);
         //设置背景颜色,目前设置为纯黑色
         mContainer.setBackgroundColor(Color.BLACK);
@@ -168,7 +173,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     @Override
     public final void setUp(String url, Map<String, String> headers) {
         if(url==null || url.length()==0){
-            VideoLogUtil.d("设置的视频链接不能为空");
+            VideoLogUtil.d("设置参数-------设置的视频链接不能为空");
         }
         mUrl = url;
         mHeaders = headers;
@@ -227,18 +232,18 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     @Override
     public void setSpeed(float speed) {
         if (speed<0){
-            VideoLogUtil.d("设置的视频播放速度不能小于0");
+            VideoLogUtil.d("设置参数-------设置的视频播放速度不能小于0");
         }
         if (mMediaPlayer instanceof IjkMediaPlayer) {
             ((IjkMediaPlayer) mMediaPlayer).setSpeed(speed);
         } else if (mMediaPlayer instanceof AndroidMediaPlayer){
             //((AndroidMediaPlayer) mMediaPlayer).setSpeed(speed);
-            VideoLogUtil.d("只有IjkPlayer才能设置播放速度");
+            VideoLogUtil.d("设置参数-------只有IjkPlayer才能设置播放速度");
         }else if(mMediaPlayer instanceof MediaPlayer){
             //((MediaPlayer) mMediaPlayer).setSpeed(speed);
-            VideoLogUtil.d("只有IjkPlayer才能设置播放速度");
+            VideoLogUtil.d("设置参数-------只有IjkPlayer才能设置播放速度");
         } else {
-            VideoLogUtil.d("只有IjkPlayer才能设置播放速度");
+            VideoLogUtil.d("设置参数-------只有IjkPlayer才能设置播放速度");
         }
     }
 
@@ -258,7 +263,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
             initMediaPlayer();
             initTextureView();
         } else {
-            VideoLogUtil.d("VideoPlayer只有在mCurrentState == STATE_IDLE时才能调用start方法.");
+            VideoLogUtil.d("播放状态--------VideoPlayer只有在mCurrentState == STATE_IDLE时才能调用start方法.");
         }
     }
 
@@ -270,7 +275,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     @Override
     public void start(long position) {
         if (position<0){
-            VideoLogUtil.d("设置开始播放的播放位置不能小于0");
+            VideoLogUtil.d("设置参数-------设置开始播放的播放位置不能小于0");
         }
         skipToPosition = position;
         start();
@@ -287,18 +292,19 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
             mMediaPlayer.start();
             mCurrentState = ConstantKeys.CurrentState.STATE_PLAYING;
             mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("STATE_PLAYING");
+            VideoLogUtil.d("播放状态--------STATE_PLAYING");
         } else if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
             //如果是缓存暂停状态,那么则继续播放
             mMediaPlayer.start();
             mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING;
             mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("STATE_BUFFERING_PLAYING");
+            VideoLogUtil.d("播放状态--------STATE_BUFFERING_PLAYING");
         } else if (mCurrentState == ConstantKeys.CurrentState.STATE_COMPLETED
                 || mCurrentState == ConstantKeys.CurrentState.STATE_ERROR) {
             //如果是完成播放或者播放错误,则重新播放
             mMediaPlayer.reset();
             openMediaPlayer();
+            VideoLogUtil.d("播放状态--------完成播放或者播放错误,则重新播放");
         } else {
             VideoLogUtil.d("VideoPlayer在mCurrentState == " + mCurrentState + "时不能调用restart()方法.");
         }
@@ -315,13 +321,13 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
             mMediaPlayer.pause();
             mCurrentState = ConstantKeys.CurrentState.STATE_PAUSED;
             mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("STATE_PAUSED");
+            VideoLogUtil.d("播放状态--------STATE_PAUSED");
         } else if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING) {
             //如果是正在缓冲状态,那么则暂停暂停缓冲
             mMediaPlayer.pause();
             mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED;
             mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("STATE_BUFFERING_PAUSED");
+            VideoLogUtil.d("播放状态--------STATE_BUFFERING_PAUSED");
         }
     }
 
@@ -333,7 +339,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
     @Override
     public void seekTo(long pos) {
         if (pos<0){
-            VideoLogUtil.d("设置开始跳转播放位置不能小于0");
+            VideoLogUtil.d("设置参数-------设置开始跳转播放位置不能小于0");
         }
         if (mMediaPlayer != null) {
             mMediaPlayer.seekTo(pos);
@@ -705,6 +711,8 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
      */
     @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     private void openMediaPlayer() {
+        //如果是重新初始化,则不用从上一次的位置继续播放
+        continueFromLastPosition(false);
         // 屏幕常亮,这个很重要,如果不设置,则看视频一会儿,屏幕会变暗
         mContainer.setKeepScreenOn(true);
         // 设置监听,可以查看ijk中的IMediaPlayer源码监听事件
@@ -760,7 +768,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         public void onPrepared(IMediaPlayer mp) {
             mCurrentState = ConstantKeys.CurrentState.STATE_PREPARED;
             mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("onPrepared ——> STATE_PREPARED");
+            VideoLogUtil.d("listener---------onPrepared ——> STATE_PREPARED");
             mp.start();
             // 从上次的保存位置播放
             if (continueFromLastPosition) {
@@ -784,7 +792,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         public void onCompletion(IMediaPlayer mp) {
             mCurrentState = ConstantKeys.CurrentState.STATE_COMPLETED;
             mController.onPlayStateChanged(mCurrentState);
-            VideoLogUtil.d("onCompletion ——> STATE_COMPLETED");
+            VideoLogUtil.d("listener---------onCompletion ——> STATE_COMPLETED");
             // 清除屏幕常亮
             mContainer.setKeepScreenOn(false);
         }
@@ -803,7 +811,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
             if (percent>MAX_PERCENT){
                 mBufferPercentage = 100;
             }
-            VideoLogUtil.d("onBufferingUpdate ——> " + percent);
+            VideoLogUtil.d("listener---------onBufferingUpdate ——> " + percent);
         }
     };
 
@@ -827,7 +835,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         public void onVideoSizeChanged(IMediaPlayer mp, int width, int height,
                                        int sar_num, int sar_den) {
             mTextureView.adaptVideoSize(width, height);
-            VideoLogUtil.d("onVideoSizeChanged ——> width:" + width + ", height:" + height);
+            VideoLogUtil.d("listener---------onVideoSizeChanged ——> width:" + width + ", height:" + height);
         }
     };
 
@@ -849,7 +857,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
                 mCurrentState = ConstantKeys.CurrentState.STATE_ERROR;
                 mController.onPlayStateChanged(mCurrentState);
             }
-            VideoLogUtil.d("onError ——> STATE_ERROR ———— what:" + what + ", extra: " + extra);
+            VideoLogUtil.d("listener---------onError ——> STATE_ERROR ———— what:" + what + ", extra: " + extra);
             return true;
         }
     };
@@ -864,16 +872,16 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
                 // 播放器开始渲染
                 mCurrentState = ConstantKeys.CurrentState.STATE_PLAYING;
                 mController.onPlayStateChanged(mCurrentState);
-                VideoLogUtil.d("onInfo ——> MEDIA_INFO_VIDEO_RENDERING_START:STATE_PLAYING");
+                VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_VIDEO_RENDERING_START:STATE_PLAYING");
             } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
                 // MediaPlayer暂时不播放,以缓冲更多的数据
                 if (mCurrentState == ConstantKeys.CurrentState.STATE_PAUSED ||
                         mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
                     mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED;
-                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PAUSED");
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PAUSED");
                 } else {
                     mCurrentState = ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING;
-                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PLAYING");
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PLAYING");
                 }
                 mController.onPlayStateChanged(mCurrentState);
             } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
@@ -881,23 +889,23 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
                 if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING) {
                     mCurrentState = ConstantKeys.CurrentState.STATE_PLAYING;
                     mController.onPlayStateChanged(mCurrentState);
-                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PLAYING");
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PLAYING");
                 }
                 if (mCurrentState == ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED) {
                     mCurrentState = ConstantKeys.CurrentState.STATE_PAUSED;
                     mController.onPlayStateChanged(mCurrentState);
-                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PAUSED");
+                    VideoLogUtil.d("listener---------onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PAUSED");
                 }
             } else if (what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED) {
                 // 视频旋转了extra度,需要恢复
                 if (mTextureView != null) {
                     mTextureView.setRotation(extra);
-                    VideoLogUtil.d("视频旋转角度:" + extra);
+                    VideoLogUtil.d("listener---------视频旋转角度:" + extra);
                 }
             } else if (what == IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
-                VideoLogUtil.d("视频不能seekTo,为直播视频");
+                VideoLogUtil.d("listener---------视频不能seekTo,为直播视频");
             } else {
-                VideoLogUtil.d("onInfo ——> what:" + what);
+                VideoLogUtil.d("listener---------onInfo ——> what:" + what);
             }
             return true;
         }
@@ -946,7 +954,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         contentView.addView(mContainer, params);
         mCurrentMode = ConstantKeys.PlayMode.MODE_FULL_SCREEN;
         mController.onPlayModeChanged(mCurrentMode);
-        VideoLogUtil.d("MODE_FULL_SCREEN");
+        VideoLogUtil.d("播放模式--------MODE_FULL_SCREEN");
     }
 
 
@@ -975,7 +983,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
 
         mCurrentMode = ConstantKeys.PlayMode.MODE_FULL_SCREEN;
         mController.onPlayModeChanged(mCurrentMode);
-        VideoLogUtil.d("MODE_FULL_SCREEN");
+        VideoLogUtil.d("播放模式--------MODE_FULL_SCREEN");
     }
 
 
@@ -1003,7 +1011,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
             this.addView(mContainer, params);
             mCurrentMode = ConstantKeys.PlayMode.MODE_NORMAL;
             mController.onPlayModeChanged(mCurrentMode);
-            VideoLogUtil.d("MODE_NORMAL");
+            VideoLogUtil.d("播放模式--------MODE_NORMAL");
             this.setOnKeyListener(null);
             return true;
         }
@@ -1035,7 +1043,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
         contentView.addView(mContainer, params);
         mCurrentMode = ConstantKeys.PlayMode.MODE_TINY_WINDOW;
         mController.onPlayModeChanged(mCurrentMode);
-        VideoLogUtil.d("MODE_TINY_WINDOW");
+        VideoLogUtil.d("播放模式-------MODE_TINY_WINDOW");
     }
 
 
@@ -1051,7 +1059,7 @@ public class VideoPlayer extends FrameLayout implements InterVideoPlayer {
             this.addView(mContainer, params);
             mCurrentMode = ConstantKeys.PlayMode.MODE_NORMAL;
             mController.onPlayModeChanged(mCurrentMode);
-            VideoLogUtil.d("MODE_NORMAL");
+            VideoLogUtil.d("播放模式-------MODE_NORMAL");
             return true;
         }
         return false;

+ 308 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/view/BaseToast.java

@@ -0,0 +1,308 @@
+/*
+Copyright 2017 yangchong211(github.com/yangchong211)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package org.yczbj.ycvideoplayerlib.view;
+
+import android.annotation.SuppressLint;
+import android.app.Application;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.os.Looper;
+import android.support.annotation.ColorInt;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.CardView;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import org.yczbj.ycvideoplayerlib.R;
+
+
+/**
+ * <pre>
+ *     @author yangchong
+ *     blog  : https://github.com/yangchong211
+ *     time  : 2017/06/4
+ *     desc  : Toast工具类,模仿易车,抖音自定义吐司
+ *     revise: 具体看GitHub开源项目:https://github.com/yangchong211/YCDialog
+ * </pre>
+ */
+public final class BaseToast {
+
+
+    @SuppressLint("StaticFieldLeak")
+    private static Context mApp;
+    private static int toastBackColor;
+
+    /**
+     * 初始化吐司工具类
+     * @param app 应用
+     */
+    public static void init(@NonNull final Context app) {
+        mApp = app;
+        toastBackColor = Color.BLACK;
+    }
+
+    public static void setToastBackColor(@ColorInt int color){
+        toastBackColor = color;
+    }
+
+    /**
+     * 私有构造
+     */
+    private BaseToast() {
+        //避免初始化
+        throw new UnsupportedOperationException("u can't instantiate me...");
+    }
+
+    /**
+     * 检查上下文不能为空,必须先进性初始化操作
+     */
+    private static void checkContext(){
+        if(mApp==null){
+            throw new NullPointerException("BaseToast context is not null,please first init");
+        }
+    }
+
+
+    /**
+     * 吐司工具类    避免点击多次导致吐司多次,最后导致Toast就长时间关闭不掉了
+     * 注意:这里如果传入context会报内存泄漏;传递activity..getApplicationContext()
+     * @param content       吐司内容
+     */
+    private static Toast toast;
+    @SuppressLint("ShowToast")
+    public static void showToast(String content) {
+        checkMainThread();
+        checkContext();
+        if (toast == null) {
+            //toast = Toast.makeText(mApp, content, Toast.LENGTH_SHORT);
+            toast = Toast.makeText(mApp, "", Toast.LENGTH_SHORT);
+            toast.setText(content);
+        } else {
+            toast.setText(content);
+        }
+        toast.show();
+    }
+
+
+    /**
+     * 某些系统可能屏蔽通知
+     * 1:检查 SystemUtils.isEnableNotification(BaseApplication.getApplication());
+     * 2:替代方案 BaseSnackBar.showSnack(topActivity, noticeStr);
+     * 圆角
+     * 屏幕中间
+     * @param notice                        内容
+     */
+    public static void showRoundRectToast(CharSequence notice) {
+        checkMainThread();
+        checkContext();
+        if (TextUtils.isEmpty(notice)){
+            return;
+        }
+        new Builder(mApp)
+                .setDuration(Toast.LENGTH_SHORT)
+                .setFill(false)
+                .setGravity(Gravity.CENTER)
+                .setOffset(0)
+                .setTitle(notice)
+                .setTextColor(Color.WHITE)
+                .setBackgroundColor(toastBackColor)
+                .setRadius(dip2px(mApp, 10))
+                .setElevation(dip2px(mApp, 0))
+                .build()
+                .show();
+    }
+
+
+    public static void showRoundRectToast(CharSequence notice,CharSequence desc) {
+        checkMainThread();
+        checkContext();
+        if (TextUtils.isEmpty(notice)){
+            return;
+        }
+        new Builder(mApp)
+                .setDuration(Toast.LENGTH_SHORT)
+                .setFill(false)
+                .setGravity(Gravity.CENTER)
+                .setOffset(0)
+                .setDesc(desc)
+                .setTitle(notice)
+                .setTextColor(Color.WHITE)
+                .setBackgroundColor(toastBackColor)
+                .setRadius(dip2px(mApp, 10))
+                .setElevation(dip2px(mApp, 0))
+                .build()
+                .show();
+    }
+
+
+
+    public static void showRoundRectToast(@LayoutRes int layout) {
+        checkMainThread();
+        checkContext();
+        if (layout==0){
+            return;
+        }
+        new Builder(mApp)
+                .setDuration(Toast.LENGTH_SHORT)
+                .setFill(false)
+                .setGravity(Gravity.CENTER)
+                .setOffset(0)
+                .setLayout(layout)
+                .build()
+                .show();
+    }
+
+
+    public static final class Builder {
+
+        private Context context;
+        private CharSequence title;
+        private CharSequence desc;
+        private int gravity = Gravity.TOP;
+        private boolean isFill;
+        private int yOffset;
+        private int duration = Toast.LENGTH_SHORT;
+        private int textColor = Color.WHITE;
+        private int backgroundColor = Color.BLACK;
+        private float radius;
+        private int elevation;
+        private int layout;
+
+
+        public Builder(Context context) {
+            this.context = context;
+        }
+
+        public Builder setTitle(CharSequence title) {
+            this.title = title;
+            return this;
+        }
+
+        public Builder setDesc(CharSequence desc){
+            this.desc = desc;
+            return this;
+        }
+
+        public Builder setGravity(int gravity) {
+            this.gravity = gravity;
+            return this;
+        }
+
+        public Builder setFill(boolean fill) {
+            isFill = fill;
+            return this;
+        }
+
+        public Builder setOffset(int yOffset) {
+            this.yOffset = yOffset;
+            return this;
+        }
+
+        public Builder setDuration(int duration) {
+            this.duration = duration;
+            return this;
+        }
+
+        public Builder setTextColor(int textColor) {
+            this.textColor = textColor;
+            return this;
+        }
+
+        public Builder setBackgroundColor(int backgroundColor) {
+            this.backgroundColor = backgroundColor;
+            return this;
+        }
+
+        public Builder setRadius(float radius) {
+            this.radius = radius;
+            return this;
+        }
+
+        public Builder setElevation(int elevation) {
+            this.elevation = elevation;
+            return this;
+        }
+
+        public Builder setLayout(@LayoutRes int layout) {
+            this.layout = layout;
+            return this;
+        }
+
+        public Toast build() {
+            if(toast==null){
+                toast = new Toast(context);
+            }
+            if (isFill) {
+                toast.setGravity(gravity | Gravity.FILL_HORIZONTAL, 0, yOffset);
+            } else {
+                toast.setGravity(gravity, 0, yOffset);
+            }
+            toast.setDuration(duration);
+            toast.setMargin(0, 0);
+            if(layout==0){
+                CardView rootView = (CardView) LayoutInflater.from(context)
+                        .inflate(R.layout.view_toast_custom, null);
+                TextView textView = rootView.findViewById(R.id.toastTextView);
+                TextView descTv = rootView.findViewById(R.id.desc);
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                    //rootView.setElevation(elevation);
+                    rootView.setCardElevation(elevation);
+                }
+                rootView.setRadius(radius);
+                rootView.setCardBackgroundColor(backgroundColor);
+                //rootView.setBackgroundColor(backgroundColor);
+                textView.setTextColor(textColor);
+                textView.setText(title);
+                if(TextUtils.isEmpty(desc)){
+                    descTv.setVisibility(View.GONE);
+                }else{
+                    descTv.setText(desc);
+                    descTv.setVisibility(View.VISIBLE);
+                }
+                toast.setView(rootView);
+            }else {
+                View view = LayoutInflater.from(context).inflate(layout, null);
+                toast.setView(view);
+            }
+            return toast;
+        }
+    }
+
+    private static int dip2px(Context context, float dpValue) {
+        final float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+
+
+    private static void checkMainThread(){
+        if (!isMainThread()){
+            throw new IllegalStateException("请不要在子线程中做弹窗操作");
+        }
+    }
+
+    private static boolean isMainThread(){
+        //是否是主线程
+        return Looper.getMainLooper() == Looper.myLooper();
+    }
+
+}

+ 51 - 0
YCVideoPlayerLib/src/main/res/layout/view_toast_custom.xml

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v7.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:card_view="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    card_view:cardBackgroundColor="@android:color/black"
+    card_view:cardCornerRadius="10dp"
+    card_view:cardElevation="0dp"
+    card_view:cardPreventCornerOverlap="true"
+    card_view:cardUseCompatPadding="false"
+    tools:ignore="MissingDefaultResource">
+
+    <LinearLayout
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:gravity="center"
+        android:layout_gravity="center"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <TextView
+            android:id="@+id/toastTextView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="visible"
+            android:gravity="center"
+            android:minEms="10"
+            android:minHeight="30dp"
+            android:padding="5dp"
+            android:text="提示标题!"
+            android:textColor="@android:color/white"
+            android:textSize="15sp" />
+
+        <TextView
+            android:id="@+id/desc"
+            android:layout_marginLeft="12dp"
+            android:layout_marginRight="12dp"
+            android:visibility="visible"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxWidth="200dp"
+            android:text="提示内容"
+            android:textColor="#ffcecece"
+            android:textSize="12sp" />
+
+    </LinearLayout>
+
+</android.support.v7.widget.CardView>

+ 19 - 0
app/src/main/java/org/yczbj/ycvideoplayer/TestTinyActivity.java

@@ -9,8 +9,10 @@ import com.bumptech.glide.Glide;
 
 import org.yczbj.ycvideoplayerlib.constant.ConstantKeys;
 import org.yczbj.ycvideoplayerlib.controller.VideoPlayerController;
+import org.yczbj.ycvideoplayerlib.inter.listener.OnVideoControlListener;
 import org.yczbj.ycvideoplayerlib.manager.VideoPlayerManager;
 import org.yczbj.ycvideoplayerlib.player.VideoPlayer;
+import org.yczbj.ycvideoplayerlib.view.BaseToast;
 
 import cn.ycbjie.ycstatusbarlib.bar.StateAppBar;
 
@@ -63,6 +65,23 @@ public class TestTinyActivity extends BaseActivity implements View.OnClickListen
                 .into(controller.imageView());
         controller.setHideTime(2000);
         controller.setTopPadding(24);
+        //设置横屏播放时,tv和audio图标是否显示
+        controller.setTvAndAudioVisibility(true,true);
+        controller.setOnVideoControlListener(new OnVideoControlListener() {
+            @Override
+            public void onVideoControlClick(int type) {
+                switch (type){
+                    case ConstantKeys.VideoControl.TV:
+                        BaseToast.showRoundRectToast("投影tv电视");
+                        break;
+                    case ConstantKeys.VideoControl.HOR_AUDIO:
+                        BaseToast.showRoundRectToast("切换音频");
+                        break;
+                    default:
+                        break;
+                }
+            }
+        });
         videoPlayer.setController(controller);
     }
 

+ 33 - 2
read/wiki1.md

@@ -8,7 +8,8 @@
 - 06.在列表中播放
 - 07.在activity播放视频处理home键逻辑
 - 08.在fragment中播放
-- 09.显示视频top[分享,下载,更多按钮控件]
+- 09.1 显示正常视频top[分享,下载,更多按钮控件]
+- 09.2 显示横屏视频top[tv投影,切换音频控件]
 - 10.全局悬浮播放视频
 - 11.常见api说明
 
@@ -32,6 +33,10 @@
     //播放视频
     videoPlayer.start();
     ```
+- 是否设置从上一次的位置继续播放,这个参数你可以自己设置,默认是true
+    ```
+    videoPlayer.continueFromLastPosition(true);
+    ```
 
 
 ### 02.竖屏全屏播放
@@ -219,7 +224,7 @@
 
 
 
-### 09.显示视频top[分享,下载,更多按钮控件]
+### 09.1 显示视频top[分享,下载,更多按钮控件]
 - 默认是不显示这几个控件的,一般实际项目中,会对播放器做很多UI方面拓展
     ```
     controller.setTopVisibility(true);
@@ -256,6 +261,32 @@
     ```
 
 
+### 09.2 显示横屏视频top[tv投影,切换音频控件]
+- 默认是不显示这几个控件的,一般实际项目中,会对播放器做很多UI方面拓展
+    ```
+    //设置横屏播放时,tv和audio图标是否显示
+    controller.setTvAndAudioVisibility(true,true);
+    ```
+- 给按钮设置点击事件
+    ```
+    controller.setOnVideoControlListener(new OnVideoControlListener() {
+        @Override
+        public void onVideoControlClick(int type) {
+            switch (type){
+                case ConstantKeys.VideoControl.TV:
+                    BaseToast.showRoundRectToast("投影tv电视");
+                    break;
+                case ConstantKeys.VideoControl.HOR_AUDIO:
+                    BaseToast.showRoundRectToast("切换音频");
+                    break;
+                default:
+                    break;
+            }
+        }
+    });
+    ```
+    
+    
 ### 10.全局悬浮播放视频
 - 代码如下所示
     ```