飞道的博客

GSYVideoPlayer播放器框架使用、播放组件源码探究(一)

680人阅读  评论(0)

 在研究GSYVideoPlayer框架源码之前,先来探究一下如果如何使用框架提供的、基础的视频播器放组件类GSYVideoPlayer.java,通过层层封装继承,可以看出它也是继承自FrameLayout这个帧布局管理类,B站的IjkVideoPlayer视频播放器组件的定义也是继承自它。

打开GSYVideoPlayer-master(官网实例demo)通过查看标准的“简单直接播放”按钮对应的标准播放器组件StandardGSYVideoPlayer.java类,可看到下图的继承关系图。

下面,为了便于分析播放器组件!为了便于分析播放器组件!为了便于分析播放器组件!重要的事情说三遍。我们的任务就是按照自定义组件的步骤流程,通过继承框架提供的视频播器放组件父类(GSYVideoPlayer.java),来抄一份StandardGSYVideoPlayer.java源码样例,我们对这个源码样例StandardGSYVideoPlayer.java进行分型,为了和这个播放器组件区分,我们创建一个空类叫MyStandardGSYVideoPlayer.java,通过Alt+Enter组合键可以查看继承GSYVideoPlayer父类所必须实现的抽象方法,也是在下面这张图中所示的:

MyStandardGSYVideoPlayer类如下:

由于这个类是一个自定义的播放器组件类,继承了 GSYVideoPlayer.java类,所以需要重写、实现父类GSYVideoPlayer中定义的一些抽象方法和接口方法,以及定义组件所必须提供的3个构造方法:


  
  1. /* @author: LQS
  2. * @date: 2020/12/15
  3. * @description:
  4. */
  5. class MyStandardGSYVideoPlayer extends GSYVideoPlayer {
  6. /**
  7. * 自定义组件的3个构造方法
  8. * @param context
  9. */
  10. public MyStandardGSYVideoPlayer(Context context) {
  11. super(context);
  12. }
  13. public MyStandardGSYVideoPlayer(Context context, AttributeSet attrs) {
  14. super(context, attrs);
  15. }
  16. public MyStandardGSYVideoPlayer(Context context, AttributeSet attrs, int defStyleAttr) {
  17. super(context, attrs, defStyleAttr);
  18. }
  19. }

可以看出主要的方法都是来自GSYVideoView和GSYVideoControlView,这两个类。

下面就是从源码样例类StandardGSYVideoPlayer.java类中复制代码到我们MyStandardGSYVideoPlayer.java类中去分析了。

首先第一大部分就是关于视频播放组件关键的变量:


  
  1. //亮度dialog
  2. protected Dialog mBrightnessDialog;
  3. //音量dialog
  4. protected Dialog mVolumeDialog;
  5. //触摸进度dialog
  6. protected Dialog mProgressDialog;
  7. //触摸进度条的progress
  8. protected ProgressBar mDialogProgressBar;
  9. //音量进度条的progress
  10. protected ProgressBar mDialogVolumeProgressBar;
  11. //亮度文本
  12. protected TextView mBrightnessDialogTv;
  13. //触摸移动显示文本
  14. protected TextView mDialogSeekTime;
  15. //触摸移动显示全部时间
  16. protected TextView mDialogTotalTime;
  17. //触摸移动方向icon
  18. protected ImageView mDialogIcon;
  19. protected Drawable mBottomProgressDrawable;
  20. protected Drawable mBottomShowProgressDrawable;
  21. protected Drawable mBottomShowProgressThumbDrawable;
  22. protected Drawable mVolumeProgressDrawable;
  23. protected Drawable mDialogProgressBarDrawable;
  24. protected int mDialogProgressHighLightColor = - 11;
  25. protected int mDialogProgressNormalColor = - 11;

关键的都注释了。

第二大部分就是关于视频播放组件布局初初始化方法:

 这部分也没事么好解释的。getLayoutId()是覆写父类GSYVideoView.java的用于指定初始化布局资源id的方法。其他的方法也是用于指定资源id的方法。


  
  1. /**
  2. * 继承后重写可替换为你需要的布局
  3. * @return
  4. */
  5. @Override
  6. public int getLayoutId() {
  7. return R.layout.video_layout_standard;
  8. }
  9. /**
  10. * 触摸进度dialog对话框的layoutId
  11. * 屏幕中心区域:触摸快进、快退进度条
  12. * 继承后重写可返回自定义
  13. * 有自定义的实现逻辑可重载showProgressDialog方法
  14. */
  15. protected int getProgressDialogLayoutId() {
  16. return com.shuyu.gsyvideoplayer.R.layout.video_progress_dialog;
  17. }
  18. /**
  19. * 触摸进度dialog对话框的进度条ProgressBar的id
  20. * 屏幕中心区域:触摸快进、快退进度条
  21. * 继承后重写可返回自定义,如果没有可返回空
  22. * 有自定义的实现逻辑可重载showProgressDialog方法
  23. */
  24. protected int getProgressDialogProgressId() {
  25. return com.shuyu.gsyvideoplayer.R.id.duration_progressbar;
  26. }
  27. /**
  28. * 触摸进度dialog对话框的当前时间文本
  29. * 屏幕中心区域:触摸快进、快退进度条
  30. * 继承后重写可返回自定义,如果没有可返回空
  31. * 有自定义的实现逻辑可重载showProgressDialog方法
  32. */
  33. protected int getProgressDialogCurrentDurationTextId() {
  34. return com.shuyu.gsyvideoplayer.R.id.tv_current;
  35. }
  36. /**
  37. * 触摸进度dialog对话框的视频总时长时间文本
  38. * 屏幕中心区域:触摸快进、快退进度条
  39. * 继承后重写可返回自定义,如果没有可返回空
  40. * 有自定义的实现逻辑可重载showProgressDialog方法
  41. */
  42. protected int getProgressDialogAllDurationTextId() {
  43. return com.shuyu.gsyvideoplayer.R.id.tv_duration;
  44. }
  45. /**
  46. * 触摸进度dialog对话框的快进、快退图片id
  47. * 屏幕中心区域:触摸快进、快退进度条
  48. * 继承后重写可返回自定义,如果没有可返回空
  49. * 有自定义的实现逻辑可重载showProgressDialog方法
  50. */
  51. protected int getProgressDialogImageId() {
  52. return com.shuyu.gsyvideoplayer.R.id.duration_image_tip;
  53. }
  54. /**
  55. * 音量dialog的layoutId
  56. * 屏幕左侧上下滑动控制音量的对话框布局
  57. * 继承后重写可返回自定义
  58. * 有自定义的实现逻辑可重载showVolumeDialog方法
  59. */
  60. protected int getVolumeLayoutId() {
  61. return com.shuyu.gsyvideoplayer.R.layout.video_volume_dialog;
  62. }
  63. /**
  64. * 音量dialog对话框的ProgressBar百分比进度条 id
  65. * 屏幕左侧上下滑动控制音量的对话框布局
  66. * 继承后重写可返回自定义,如果没有可返回空
  67. * 有自定义的实现逻辑可重载showVolumeDialog方法
  68. */
  69. protected int getVolumeProgressId() {
  70. return com.shuyu.gsyvideoplayer.R.id.volume_progressbar;
  71. }
  72. /**
  73. * 亮度dialog对话框的layoutId
  74. * 屏幕右侧上下滑动控制亮度的对话框布局
  75. * 继承后重写可返回自定义
  76. * 有自定义的实现逻辑可重载showBrightnessDialog方法
  77. */
  78. protected int getBrightnessLayoutId() {
  79. return com.shuyu.gsyvideoplayer.R.layout.video_brightness;
  80. }
  81. /**
  82. * 亮度dialog的百分比text id
  83. * 屏幕右侧上下滑动控制亮度的对话框布局
  84. * 继承后重写可返回自定义,如果没有可返回空
  85. * 有自定义的实现逻辑可重载showBrightnessDialog方法
  86. */
  87. protected int getBrightnessTextId() {
  88. return com.shuyu.gsyvideoplayer.R.id.app_video_brightness;
  89. }

第三大部分就是关于视频播放组件根据播放状态显示/隐藏UI按钮方法: 

这里需要给出示意图说明一下播放组件的屏幕组成结构:①顶部返回按钮和视频标题;②中部的播放/暂停按钮、触摸滑动时的快进/快退图标和进度条;③底部的当前播放点时间文本/视频总时长和进度条;④以及最下面的视频预加载进度条;

这里面会有一个逻辑当点击屏幕时所有的UI按钮、图标、文本信息和都会显示,2.5秒之内再次点击屏幕,所有的UI按钮、图标、文本信息会立即隐藏,若2.5秒之后不点击屏幕也会自动隐藏(这个后面会说),代码如下:


  
  1. /********************************根据播放状态控制UI显示的方法*********************************************/
  2. @Override
  3. protected void changeUiToPlayingShow() {
  4. Debuger.printfLog( "changeUiToPlayingShow");
  5. //顶部返回按钮和标题根布局
  6. setViewShowState(mTopContainer, VISIBLE);
  7. //底部播放时长文本和进度条、全屏按钮的根布局
  8. setViewShowState(mBottomContainer, VISIBLE);
  9. //屏幕中间区域开始、暂停按钮
  10. setViewShowState(mStartButton, VISIBLE);
  11. //屏幕中心区域,和播放/暂停按钮同一位置处的Loading加载中图标,它是一个自定义的组件moe.codeest.enviews.ENDownloadView
  12. setViewShowState(mLoadingProgressBar, INVISIBLE);
  13. //视频封面的父布局,这个即使一个空的相对布局
  14. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  15. //底部进度调,应该是缓存进度条
  16. setViewShowState(mBottomProgressBar, INVISIBLE);
  17. setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
  18. if (mLoadingProgressBar instanceof ENDownloadView) {
  19. ((ENDownloadView) mLoadingProgressBar).reset();
  20. }
  21. updateStartImage();
  22. }
  23. /*下面的所有方法注释不再给出,因为和上面播放时控制的变量都是一样的,只不过显示/隐藏值不同罢了
  24. */
  25. /**
  26. * 点击触摸显示和隐藏逻辑
  27. * 在控制播放按钮自动隐藏前,通过点击屏幕使得控制播放按钮隐藏、显示的逻辑
  28. */
  29. @Override
  30. protected void onClickUiToggle() {
  31. if (mIfCurrentIsFullscreen && mLockCurScreen && mNeedLockFull) {
  32. setViewShowState(mLockScreen, VISIBLE);
  33. return;
  34. }
  35. if (mCurrentState == CURRENT_STATE_PREPAREING) {
  36. if (mBottomContainer != null) {
  37. if (mBottomContainer.getVisibility() == View.VISIBLE) {
  38. changeUiToPrepareingClear();
  39. } else {
  40. changeUiToPreparingShow();
  41. }
  42. }
  43. } else if (mCurrentState == CURRENT_STATE_PLAYING) {
  44. if (mBottomContainer != null) {
  45. if (mBottomContainer.getVisibility() == View.VISIBLE) {
  46. changeUiToPlayingClear();
  47. } else {
  48. changeUiToPlayingShow();
  49. }
  50. }
  51. } else if (mCurrentState == CURRENT_STATE_PAUSE) {
  52. if (mBottomContainer != null) {
  53. if (mBottomContainer.getVisibility() == View.VISIBLE) {
  54. changeUiToPauseClear();
  55. } else {
  56. changeUiToPauseShow();
  57. }
  58. }
  59. } else if (mCurrentState == CURRENT_STATE_AUTO_COMPLETE) {
  60. if (mBottomContainer != null) {
  61. if (mBottomContainer.getVisibility() == View.VISIBLE) {
  62. changeUiToCompleteClear();
  63. } else {
  64. changeUiToCompleteShow();
  65. }
  66. }
  67. } else if (mCurrentState == CURRENT_STATE_PLAYING_BUFFERING_START) {
  68. if (mBottomContainer != null) {
  69. if (mBottomContainer.getVisibility() == View.VISIBLE) {
  70. changeUiToPlayingBufferingClear();
  71. } else {
  72. changeUiToPlayingBufferingShow();
  73. }
  74. }
  75. }
  76. }
  77. @Override
  78. protected void changeUiToNormal() {
  79. Debuger.printfLog( "changeUiToNormal");
  80. //设置组件显示、隐藏:view.setVisibility(visibility);
  81. setViewShowState(mTopContainer, VISIBLE);
  82. setViewShowState(mBottomContainer, INVISIBLE);
  83. setViewShowState(mStartButton, VISIBLE);
  84. setViewShowState(mLoadingProgressBar, INVISIBLE);
  85. setViewShowState(mThumbImageViewLayout, VISIBLE);
  86. setViewShowState(mBottomProgressBar, INVISIBLE);
  87. setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
  88. updateStartImage();
  89. if (mLoadingProgressBar instanceof ENDownloadView) {
  90. ((ENDownloadView) mLoadingProgressBar).reset();
  91. }
  92. }
  93. @Override
  94. protected void changeUiToPreparingShow() {
  95. Debuger.printfLog( "changeUiToPreparingShow");
  96. setViewShowState(mTopContainer, VISIBLE);
  97. setViewShowState(mBottomContainer, VISIBLE);
  98. setViewShowState(mStartButton, INVISIBLE);
  99. setViewShowState(mLoadingProgressBar, VISIBLE);
  100. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  101. setViewShowState(mBottomProgressBar, INVISIBLE);
  102. setViewShowState(mLockScreen, GONE);
  103. if (mLoadingProgressBar instanceof ENDownloadView) {
  104. ENDownloadView enDownloadView = (ENDownloadView) mLoadingProgressBar;
  105. if (enDownloadView.getCurrentState() == ENDownloadView.STATE_PRE) {
  106. ((ENDownloadView) mLoadingProgressBar).start();
  107. }
  108. }
  109. }
  110. @Override
  111. protected void changeUiToPauseShow() {
  112. Debuger.printfLog( "changeUiToPauseShow");
  113. setViewShowState(mTopContainer, VISIBLE);
  114. setViewShowState(mBottomContainer, VISIBLE);
  115. setViewShowState(mStartButton, VISIBLE);
  116. setViewShowState(mLoadingProgressBar, INVISIBLE);
  117. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  118. setViewShowState(mBottomProgressBar, INVISIBLE);
  119. setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
  120. if (mLoadingProgressBar instanceof ENDownloadView) {
  121. ((ENDownloadView) mLoadingProgressBar).reset();
  122. }
  123. updateStartImage();
  124. updatePauseCover();
  125. }
  126. @Override
  127. protected void changeUiToCompleteShow() {
  128. Debuger.printfLog( "changeUiToCompleteShow");
  129. setViewShowState(mTopContainer, VISIBLE);
  130. setViewShowState(mBottomContainer, VISIBLE);
  131. setViewShowState(mStartButton, VISIBLE);
  132. setViewShowState(mLoadingProgressBar, INVISIBLE);
  133. setViewShowState(mThumbImageViewLayout, VISIBLE);
  134. setViewShowState(mBottomProgressBar, INVISIBLE);
  135. setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
  136. if (mLoadingProgressBar instanceof ENDownloadView) {
  137. ((ENDownloadView) mLoadingProgressBar).reset();
  138. }
  139. updateStartImage();
  140. }
  141. @Override
  142. protected void changeUiToError() {
  143. Debuger.printfLog( "changeUiToError");
  144. setViewShowState(mTopContainer, INVISIBLE);
  145. setViewShowState(mBottomContainer, INVISIBLE);
  146. setViewShowState(mStartButton, VISIBLE);
  147. setViewShowState(mLoadingProgressBar, INVISIBLE);
  148. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  149. setViewShowState(mBottomProgressBar, INVISIBLE);
  150. setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
  151. if (mLoadingProgressBar instanceof ENDownloadView) {
  152. ((ENDownloadView) mLoadingProgressBar).reset();
  153. }
  154. updateStartImage();
  155. }
  156. @Override
  157. protected void changeUiToPlayingBufferingShow() {
  158. Debuger.printfLog( "changeUiToPlayingBufferingShow");
  159. setViewShowState(mTopContainer, VISIBLE);
  160. setViewShowState(mBottomContainer, VISIBLE);
  161. setViewShowState(mStartButton, INVISIBLE);
  162. setViewShowState(mLoadingProgressBar, VISIBLE);
  163. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  164. setViewShowState(mBottomProgressBar, INVISIBLE);
  165. setViewShowState(mLockScreen, GONE);
  166. if (mLoadingProgressBar instanceof ENDownloadView) {
  167. ENDownloadView enDownloadView = (ENDownloadView) mLoadingProgressBar;
  168. if (enDownloadView.getCurrentState() == ENDownloadView.STATE_PRE) {
  169. ((ENDownloadView) mLoadingProgressBar).start();
  170. }
  171. }
  172. }
  173. /********************************根据播放状态控制UI隐藏的方法*********************************************/
  174. /**
  175. * 隐藏所有关于播放的信息:顶部返回按钮和标题栏,中部的开始/暂停/加载中按钮图标,底部的播放时长文本、进度条和全屏按钮
  176. */
  177. @Override
  178. protected void hideAllWidget() {
  179. setViewShowState(mBottomContainer, INVISIBLE);
  180. setViewShowState(mTopContainer, INVISIBLE);
  181. setViewShowState(mBottomProgressBar, VISIBLE);
  182. setViewShowState(mStartButton, INVISIBLE);
  183. }
  184. protected void changeUiToPrepareingClear() {
  185. Debuger.printfLog( "changeUiToPrepareingClear");
  186. setViewShowState(mTopContainer, INVISIBLE);
  187. setViewShowState(mBottomContainer, INVISIBLE);
  188. setViewShowState(mStartButton, INVISIBLE);
  189. setViewShowState(mLoadingProgressBar, INVISIBLE);
  190. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  191. setViewShowState(mBottomProgressBar, INVISIBLE);
  192. setViewShowState(mLockScreen, GONE);
  193. if (mLoadingProgressBar instanceof ENDownloadView) {
  194. ((ENDownloadView) mLoadingProgressBar).reset();
  195. }
  196. }
  197. protected void changeUiToPlayingClear() {
  198. Debuger.printfLog( "changeUiToPlayingClear");
  199. changeUiToClear();
  200. setViewShowState(mBottomProgressBar, VISIBLE);
  201. }
  202. protected void changeUiToPauseClear() {
  203. Debuger.printfLog( "changeUiToPauseClear");
  204. changeUiToClear();
  205. setViewShowState(mBottomProgressBar, VISIBLE);
  206. updatePauseCover();
  207. }
  208. protected void changeUiToPlayingBufferingClear() {
  209. Debuger.printfLog( "changeUiToPlayingBufferingClear");
  210. setViewShowState(mTopContainer, INVISIBLE);
  211. setViewShowState(mBottomContainer, INVISIBLE);
  212. setViewShowState(mStartButton, INVISIBLE);
  213. setViewShowState(mLoadingProgressBar, VISIBLE);
  214. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  215. setViewShowState(mBottomProgressBar, VISIBLE);
  216. setViewShowState(mLockScreen, GONE);
  217. if (mLoadingProgressBar instanceof ENDownloadView) {
  218. ENDownloadView enDownloadView = (ENDownloadView) mLoadingProgressBar;
  219. if (enDownloadView.getCurrentState() == ENDownloadView.STATE_PRE) {
  220. ((ENDownloadView) mLoadingProgressBar).start();
  221. }
  222. }
  223. updateStartImage();
  224. }
  225. protected void changeUiToClear() {
  226. Debuger.printfLog( "changeUiToClear");
  227. setViewShowState(mTopContainer, INVISIBLE);
  228. setViewShowState(mBottomContainer, INVISIBLE);
  229. setViewShowState(mStartButton, INVISIBLE);
  230. setViewShowState(mLoadingProgressBar, INVISIBLE);
  231. setViewShowState(mThumbImageViewLayout, INVISIBLE);
  232. setViewShowState(mBottomProgressBar, INVISIBLE);
  233. setViewShowState(mLockScreen, GONE);
  234. if (mLoadingProgressBar instanceof ENDownloadView) {
  235. ((ENDownloadView) mLoadingProgressBar).reset();
  236. }
  237. }
  238. protected void changeUiToCompleteClear() {
  239. Debuger.printfLog( "changeUiToCompleteClear");
  240. setViewShowState(mTopContainer, INVISIBLE);
  241. setViewShowState(mBottomContainer, INVISIBLE);
  242. setViewShowState(mStartButton, VISIBLE);
  243. setViewShowState(mLoadingProgressBar, INVISIBLE);
  244. setViewShowState(mThumbImageViewLayout, VISIBLE);
  245. setViewShowState(mBottomProgressBar, VISIBLE);
  246. setViewShowState(mLockScreen, (mIfCurrentIsFullscreen && mNeedLockFull) ? VISIBLE : GONE);
  247. if (mLoadingProgressBar instanceof ENDownloadView) {
  248. ((ENDownloadView) mLoadingProgressBar).reset();
  249. }
  250. updateStartImage();
  251. }
  252. /**
  253. * 根据播放状态设置对应的播放、暂停、出错状态
  254. */
  255. protected void updateStartImage() {
  256. if (mStartButton instanceof ENPlayView) {
  257. ENPlayView enPlayView = (ENPlayView) mStartButton;
  258. enPlayView.setDuration( 500);
  259. if (mCurrentState == CURRENT_STATE_PLAYING) {
  260. enPlayView.play();
  261. } else if (mCurrentState == CURRENT_STATE_ERROR) {
  262. enPlayView.pause();
  263. } else {
  264. enPlayView.pause();
  265. }
  266. } else if (mStartButton instanceof ImageView) {
  267. ImageView imageView = (ImageView) mStartButton;
  268. if (mCurrentState == CURRENT_STATE_PLAYING) {
  269. imageView.setImageResource(com.shuyu.gsyvideoplayer.R.drawable.video_click_pause_selector);
  270. } else if (mCurrentState == CURRENT_STATE_ERROR) {
  271. imageView.setImageResource(com.shuyu.gsyvideoplayer.R.drawable.video_click_error_selector);
  272. } else {
  273. imageView.setImageResource(com.shuyu.gsyvideoplayer.R.drawable.video_click_play_selector);
  274. }
  275. }
  276. }

第四大部分就是关于视频播放组件如果有自定义Drawable时对其初始化设置的:


  
  1. /**
  2. * 正常小屏时,如果有自定义Drawable,则初始化设置这些Drawable
  3. */
  4. @Override
  5. protected void init(Context context) {
  6. super.init(context);
  7. //增加自定义ui
  8. if (mBottomProgressDrawable != null) {
  9. mBottomProgressBar.setProgressDrawable(mBottomProgressDrawable);
  10. }
  11. if (mBottomShowProgressDrawable != null) {
  12. mProgressBar.setProgressDrawable(mBottomProgressDrawable);
  13. }
  14. if (mBottomShowProgressThumbDrawable != null) {
  15. mProgressBar.setThumb(mBottomShowProgressThumbDrawable);
  16. }
  17. }
  18. /**
  19. * 全屏的UI逻辑:指的是如果在小屏-全屏-小屏之间切换时,有自定义Drawable,则将几个地方的样式也设置到全屏
  20. */
  21. private void initFullUI(MyStandardGSYVideoPlayer myStandardGSYVideoPlayer) {
  22. if (mBottomProgressDrawable != null) {
  23. myStandardGSYVideoPlayer.setBottomProgressBarDrawable(mBottomProgressDrawable);
  24. }
  25. if (mBottomShowProgressDrawable != null && mBottomShowProgressThumbDrawable != null) {
  26. myStandardGSYVideoPlayer.setBottomShowProgressBarDrawable(mBottomShowProgressDrawable,
  27. mBottomShowProgressThumbDrawable);
  28. }
  29. if (mVolumeProgressDrawable != null) {
  30. myStandardGSYVideoPlayer.setDialogVolumeProgressBar(mVolumeProgressDrawable);
  31. }
  32. if (mDialogProgressBarDrawable != null) {
  33. myStandardGSYVideoPlayer.setDialogProgressBar(mDialogProgressBarDrawable);
  34. }
  35. if (mDialogProgressHighLightColor >= 0 && mDialogProgressNormalColor >= 0) {
  36. myStandardGSYVideoPlayer.setDialogProgressColor(mDialogProgressHighLightColor, mDialogProgressNormalColor);
  37. }
  38. }
  39. /**
  40. * 底部进度条-弹出的
  41. */
  42. public void setBottomShowProgressBarDrawable(Drawable drawable, Drawable thumb) {
  43. mBottomShowProgressDrawable = drawable;
  44. mBottomShowProgressThumbDrawable = thumb;
  45. if (mProgressBar != null) {
  46. mProgressBar.setProgressDrawable(drawable);
  47. mProgressBar.setThumb(thumb);
  48. }
  49. }
  50. /**
  51. * 底部进度条-非弹出
  52. */
  53. public void setBottomProgressBarDrawable(Drawable drawable) {
  54. mBottomProgressDrawable = drawable;
  55. if (mBottomProgressBar != null) {
  56. mBottomProgressBar.setProgressDrawable(drawable);
  57. }
  58. }
  59. /**
  60. * 声音进度条
  61. */
  62. public void setDialogVolumeProgressBar(Drawable drawable) {
  63. mVolumeProgressDrawable = drawable;
  64. }
  65. /**
  66. * 中间进度条
  67. */
  68. public void setDialogProgressBar(Drawable drawable) {
  69. mDialogProgressBarDrawable = drawable;
  70. }
  71. /**
  72. * 中间进度条字体颜色
  73. */
  74. public void setDialogProgressColor(int highLightColor, int normalColor) {
  75. mDialogProgressHighLightColor = highLightColor;
  76. mDialogProgressNormalColor = normalColor;
  77. }

第五部分亮度Dialog、音量Dialog、快进快退Dialog显示隐藏及数值变化逻辑的控制:

效果图如下:

  

代码如下:


  
  1. /************************************* 亮度Dialog、音量Dialog、快进快退Dialog显示隐藏及数值变化逻辑的控制****************************************/
  2. /**
  3. * 显示wifi确定框,如需要自定义继承重写即可
  4. */
  5. @Override
  6. protected void showWifiDialog() {
  7. if (!NetworkUtils.isAvailable(mContext)) {
  8. //Toast.makeText(mContext, getResources().getString(R.string.no_net), Toast.LENGTH_LONG).show();
  9. startPlayLogic();
  10. return;
  11. }
  12. AlertDialog.Builder builder = new AlertDialog.Builder(getActivityContext());
  13. builder.setMessage(getResources().getString(R.string.tips_not_wifi));
  14. builder.setPositiveButton(getResources().getString(R.string.tips_not_wifi_confirm), new DialogInterface.OnClickListener() {
  15. @Override
  16. public void onClick(DialogInterface dialog, int which) {
  17. dialog.dismiss();
  18. startPlayLogic();
  19. }
  20. });
  21. builder.setNegativeButton(getResources().getString(R.string.tips_not_wifi_cancel), new DialogInterface.OnClickListener() {
  22. @Override
  23. public void onClick(DialogInterface dialog, int which) {
  24. dialog.dismiss();
  25. }
  26. });
  27. builder.create().show();
  28. }
  29. /**
  30. * 触摸显示滑动进度dialog,如需要自定义继承重写即可,记得重写dismissProgressDialog
  31. * 滑动快进、快退进度条、当前播放时间文本、总时长文本
  32. * 在protected void touchSurfaceMove(float deltaX, float deltaY, float y)中调用
  33. */
  34. @Override
  35. @SuppressWarnings("ResourceType")
  36. protected void showProgressDialog(float deltaX, String seekTime, int seekTimePosition, String totalTime, int totalTimeDuration) {
  37. if (mProgressDialog == null) {
  38. View localView = LayoutInflater.from(getActivityContext()).inflate(getProgressDialogLayoutId(), null);
  39. //ProgressBar 滑动进度条
  40. if (localView.findViewById(getProgressDialogProgressId()) instanceof ProgressBar) {
  41. mDialogProgressBar = ((ProgressBar) localView.findViewById(getProgressDialogProgressId()));
  42. if (mDialogProgressBarDrawable != null) {
  43. mDialogProgressBar.setProgressDrawable(mDialogProgressBarDrawable);
  44. }
  45. }
  46. //当前视频播放时间文本
  47. if (localView.findViewById(getProgressDialogCurrentDurationTextId()) instanceof TextView) {
  48. mDialogSeekTime = ((TextView) localView.findViewById(getProgressDialogCurrentDurationTextId()));
  49. }
  50. //视频总时长文本
  51. if (localView.findViewById(getProgressDialogAllDurationTextId()) instanceof TextView) {
  52. mDialogTotalTime = ((TextView) localView.findViewById(getProgressDialogAllDurationTextId()));
  53. }
  54. if (localView.findViewById(getProgressDialogImageId()) instanceof ImageView) {
  55. mDialogIcon = ((ImageView) localView.findViewById(getProgressDialogImageId()));
  56. }
  57. //初始化一个带样式的对话框
  58. mProgressDialog = new Dialog(getActivityContext(), R.style.video_style_dialog_progress);
  59. mProgressDialog.setContentView(localView);
  60. mProgressDialog.getWindow().addFlags(Window.FEATURE_ACTION_BAR);
  61. mProgressDialog.getWindow().addFlags( 32);
  62. mProgressDialog.getWindow().addFlags( 16);
  63. mProgressDialog.getWindow().setLayout(getWidth(), getHeight());
  64. if (mDialogProgressNormalColor != - 11 && mDialogTotalTime != null) {
  65. mDialogTotalTime.setTextColor(mDialogProgressNormalColor);
  66. }
  67. if (mDialogProgressHighLightColor != - 11 && mDialogSeekTime != null) {
  68. mDialogSeekTime.setTextColor(mDialogProgressHighLightColor);
  69. }
  70. WindowManager.LayoutParams localLayoutParams = mProgressDialog.getWindow().getAttributes();
  71. localLayoutParams.gravity = Gravity.TOP;
  72. localLayoutParams.width = getWidth();
  73. localLayoutParams.height = getHeight();
  74. int location[] = new int[ 2];
  75. //获取控件在当前屏幕中的位置
  76. getLocationOnScreen(location);
  77. localLayoutParams.x = location[ 0];
  78. localLayoutParams.y = location[ 1];
  79. mProgressDialog.getWindow().setAttributes(localLayoutParams);
  80. }
  81. if (!mProgressDialog.isShowing()) {
  82. mProgressDialog.show();
  83. }
  84. if (mDialogSeekTime != null) {
  85. mDialogSeekTime.setText(seekTime);
  86. }
  87. if (mDialogTotalTime != null) {
  88. mDialogTotalTime.setText( " / " + totalTime);
  89. }
  90. if (totalTimeDuration > 0)
  91. if (mDialogProgressBar != null) {
  92. mDialogProgressBar.setProgress(seekTimePosition * 100 / totalTimeDuration);
  93. }
  94. if (deltaX > 0) {
  95. if (mDialogIcon != null) {
  96. mDialogIcon.setBackgroundResource(R.drawable.video_forward_icon);
  97. }
  98. } else {
  99. if (mDialogIcon != null) {
  100. mDialogIcon.setBackgroundResource(R.drawable.video_backward_icon);
  101. }
  102. }
  103. }
  104. @Override
  105. protected void dismissProgressDialog() {
  106. if (mProgressDialog != null) {
  107. mProgressDialog.dismiss();
  108. mProgressDialog = null;
  109. }
  110. }
  111. /**
  112. * 触摸音量dialog,如需要自定义继承重写即可,记得重写dismissVolumeDialog
  113. */
  114. @Override
  115. protected void showVolumeDialog(float deltaY, int volumePercent) {
  116. if (mVolumeDialog == null) {
  117. View localView = LayoutInflater.from(getActivityContext()).inflate(getVolumeLayoutId(), null);
  118. if (localView.findViewById(getVolumeProgressId()) instanceof ProgressBar) {
  119. mDialogVolumeProgressBar = ((ProgressBar) localView.findViewById(getVolumeProgressId()));
  120. if (mVolumeProgressDrawable != null && mDialogVolumeProgressBar != null) {
  121. mDialogVolumeProgressBar.setProgressDrawable(mVolumeProgressDrawable);
  122. }
  123. }
  124. mVolumeDialog = new Dialog(getActivityContext(), R.style.video_style_dialog_progress);
  125. mVolumeDialog.setContentView(localView);
  126. mVolumeDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
  127. mVolumeDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
  128. mVolumeDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
  129. mVolumeDialog.getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  130. WindowManager.LayoutParams localLayoutParams = mVolumeDialog.getWindow().getAttributes();
  131. localLayoutParams.gravity = Gravity.TOP | Gravity.START;
  132. localLayoutParams.width = getWidth();
  133. localLayoutParams.height = getHeight();
  134. int location[] = new int[ 2];
  135. getLocationOnScreen(location);
  136. localLayoutParams.x = location[ 0];
  137. localLayoutParams.y = location[ 1];
  138. mVolumeDialog.getWindow().setAttributes(localLayoutParams);
  139. }
  140. if (!mVolumeDialog.isShowing()) {
  141. mVolumeDialog.show();
  142. }
  143. if (mDialogVolumeProgressBar != null) {
  144. mDialogVolumeProgressBar.setProgress(volumePercent);
  145. }
  146. }
  147. @Override
  148. protected void dismissVolumeDialog() {
  149. if (mVolumeDialog != null) {
  150. mVolumeDialog.dismiss();
  151. mVolumeDialog = null;
  152. }
  153. }
  154. /**
  155. * 触摸亮度dialog,如需要自定义继承重写即可,记得重写dismissBrightnessDialog
  156. */
  157. @Override
  158. protected void showBrightnessDialog(float percent) {
  159. if (mBrightnessDialog == null) {
  160. View localView = LayoutInflater.from(getActivityContext()).inflate(getBrightnessLayoutId(), null);
  161. if (localView.findViewById(getBrightnessTextId()) instanceof TextView) {
  162. mBrightnessDialogTv = (TextView) localView.findViewById(getBrightnessTextId());
  163. }
  164. mBrightnessDialog = new Dialog(getActivityContext(), R.style.video_style_dialog_progress);
  165. mBrightnessDialog.setContentView(localView);
  166. mBrightnessDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
  167. mBrightnessDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
  168. mBrightnessDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
  169. mBrightnessDialog.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
  170. mBrightnessDialog.getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  171. WindowManager.LayoutParams localLayoutParams = mBrightnessDialog.getWindow().getAttributes();
  172. localLayoutParams.gravity = Gravity.TOP | Gravity.END;
  173. localLayoutParams.width = getWidth();
  174. localLayoutParams.height = getHeight();
  175. int location[] = new int[ 2];
  176. getLocationOnScreen(location);
  177. localLayoutParams.x = location[ 0];
  178. localLayoutParams.y = location[ 1];
  179. mBrightnessDialog.getWindow().setAttributes(localLayoutParams);
  180. }
  181. if (!mBrightnessDialog.isShowing()) {
  182. mBrightnessDialog.show();
  183. }
  184. if (mBrightnessDialogTv != null)
  185. mBrightnessDialogTv.setText(( int) (percent * 100) + "%");
  186. }
  187. @Override
  188. protected void dismissBrightnessDialog() {
  189. if (mBrightnessDialog != null) {
  190. mBrightnessDialog.dismiss();
  191. mBrightnessDialog = null;
  192. }
  193. }
  194. @Override
  195. protected void onDetachedFromWindow() {
  196. super.onDetachedFromWindow();
  197. dismissVolumeDialog();
  198. dismissBrightnessDialog();
  199. }

第六部分正常小屏--全屏--小屏进行切换时,需要将当前正在播放的信息、样式复制给将要使用的屏幕模式

这里只是参数的拷贝,没有涉及到全屏-小屏切换按钮的逻辑,在 GSYVideoPlayer播放器框架使用、播放组件源码探究(三)中补充讲解。


  
  1. /**
  2. * 全屏-小屏-全屏相互切换时,将当前播放时间点、视频时长、进度条百分比进度拷贝给播放器对象
  3. * @param from
  4. * @param to
  5. */
  6. @Override
  7. protected void cloneParams(GSYBaseVideoPlayer from, GSYBaseVideoPlayer to) {
  8. super.cloneParams(from, to);
  9. MyStandardGSYVideoPlayer sf = (MyStandardGSYVideoPlayer) from;
  10. MyStandardGSYVideoPlayer st = (MyStandardGSYVideoPlayer) to;
  11. if (st.mProgressBar != null && sf.mProgressBar != null) {
  12. st.mProgressBar.setProgress(sf.mProgressBar.getProgress());
  13. st.mProgressBar.setSecondaryProgress(sf.mProgressBar.getSecondaryProgress());
  14. }
  15. if (st.mTotalTimeTextView != null && sf.mTotalTimeTextView != null) {
  16. st.mTotalTimeTextView.setText(sf.mTotalTimeTextView.getText());
  17. }
  18. if (st.mCurrentTimeTextView != null && sf.mCurrentTimeTextView != null) {
  19. st.mCurrentTimeTextView.setText(sf.mCurrentTimeTextView.getText());
  20. }
  21. }
  22. /**
  23. * 将自定义的效果也设置到全屏
  24. *
  25. * @param context
  26. * @param actionBar 是否有actionBar,有的话需要隐藏
  27. * @param statusBar 是否有状态bar,有的话需要隐藏
  28. * @return
  29. */
  30. @Override
  31. public GSYBaseVideoPlayer startWindowFullscreen(Context context, boolean actionBar, boolean statusBar) {
  32. GSYBaseVideoPlayer gsyBaseVideoPlayer = super.startWindowFullscreen(context, actionBar, statusBar);
  33. if (gsyBaseVideoPlayer != null) {
  34. MyStandardGSYVideoPlayer gsyVideoPlayer = (MyStandardGSYVideoPlayer) gsyBaseVideoPlayer;
  35. gsyVideoPlayer.setLockClickListener(mLockClickListener);
  36. gsyVideoPlayer.setNeedLockFull(isNeedLockFull());
  37. initFullUI(gsyVideoPlayer);
  38. //比如你自定义了返回案件,但是因为返回按键底层已经设置了返回事件,所以你需要在这里重新增加的逻辑
  39. }
  40. return gsyBaseVideoPlayer;
  41. }

第七部分关于截图功能:

关于截图这块是扩展功能,可暂时忽略,后面需要时再研究。 


  
  1. /************************************* 关于截图的 ****************************************/
  2. /**
  3. * 获取截图
  4. */
  5. public void taskShotPic(GSYVideoShotListener gsyVideoShotListener) {
  6. this.taskShotPic(gsyVideoShotListener, false);
  7. }
  8. /**
  9. * 获取截图
  10. *
  11. * @param high 是否需要高清的
  12. */
  13. public void taskShotPic(GSYVideoShotListener gsyVideoShotListener, boolean high) {
  14. if (getCurrentPlayer().getRenderProxy() != null) {
  15. getCurrentPlayer().getRenderProxy().taskShotPic(gsyVideoShotListener, high);
  16. }
  17. }
  18. /**
  19. * 保存截图
  20. */
  21. public void saveFrame(final File file, GSYVideoShotSaveListener gsyVideoShotSaveListener) {
  22. saveFrame(file, false, gsyVideoShotSaveListener);
  23. }
  24. /**
  25. * 保存截图
  26. *
  27. * @param high 是否需要高清的
  28. */
  29. public void saveFrame(final File file, final boolean high, final GSYVideoShotSaveListener gsyVideoShotSaveListener) {
  30. if (getCurrentPlayer().getRenderProxy() != null) {
  31. getCurrentPlayer().getRenderProxy().saveFrame(file, high, gsyVideoShotSaveListener);
  32. }
  33. }

第八部分贴出开始播放的逻辑代码,这个比较少:


  
  1. /**
  2. * 开始播放
  3. */
  4. @Override
  5. public void startPlayLogic() {
  6. if (mVideoAllCallBack != null) {
  7. Debuger.printfLog( "onClickStartThumb");
  8. mVideoAllCallBack.onClickStartThumb(mOriginUrl, mTitle, MyStandardGSYVideoPlayer. this);
  9. }
  10. /**
  11. * 父类GSYVideoControlView方法:增对列表优化,在播放前的时候才进行setup
  12. * 优化内容:
  13. * 设置播放URL
  14. * @param url 播放url
  15. * @param cacheWithPlay 是否边播边缓存
  16. * @param cachePath 缓存路径,如果是M3U8或者HLS,请设置为false
  17. * @param mapHeadData 头部信息
  18. * @param title title
  19. */
  20. prepareVideo();
  21. /**
  22. * 开始对视频播放组件上层的播放、暂停、播放进度条、播放时间/总时长等按钮的显示/隐藏进行控制
  23. *
  24. * protected int mDismissControlTime = 2500; 触摸显示后隐藏的时间:触摸显示控制按钮,2.5秒后隐藏所有控制按钮
  25. * Runnable dismissControlTask = new Runnable(); 通过postDelayed()延时2.5秒后向消息队列发送一个可执行的子线程消息,去隐藏控制按钮更新界面
  26. */
  27. startDismissControlViewTimer();
  28. }
  29. /**
  30. * 重新开启进度查询以及控制view消失的定时任务
  31. * 用于解决GSYVideoHelper中通过removeview方式做全屏切换导致的定时任务停止的问题
  32. * GSYVideoControlView onDetachedFromWindow()
  33. */
  34. public void restartTimerTask() {
  35. startProgressTimer();
  36. startDismissControlViewTimer();
  37. }

好了到这里源码样例类StandardGSYVideoPlayer.java类的代码基本都分析完了 ,都在注释里,可以细细的品!

下面来说两部分,自动隐藏播放界面上层的UI按钮、图标、文本信息和通过手势滑动控制音量Dialog、进度条Dialog、屏幕亮度Dialog的逻辑,鉴于篇幅过长,将总结到第二篇。

GSYVideoPlayer播放器框架使用、播放组件源码探究(二):https://blog.csdn.net/luqingshuai_eloong/article/details/111318995

 


转载:https://blog.csdn.net/luqingshuai_eloong/article/details/111209282
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场