上一篇中,我们实现了仿抖音上下翻页切换视频的效果,详见【Android 进阶】仿抖音系列之翻页上下滑切换视频(一),这一篇,我们来实现抖音列表播放视频。

之前也在github上找到一个demo,这是链接,原理和我的一样,只是用起来比较麻烦。。。

先说下原理,这里用到了RecyclerView的onScrolled和onScrollStateChanged 监听,在onScrolled中判断当前可见的position,结合onScrollStateChanged中返回的当前RecyclerView的滑动状态,当是拖动和停止滚动时,可以播放;当是惯性滑动时,暂停播放。

关于RecyclerView3种滑动状态,RecyclerView.SCROLL_STATE_IDLE,RecyclerView.SCROLL_STATE_DRAGGING,RecyclerView.SCROLL_STATE_SETTLING,大家可以自行百度,这里不做过多的描述了。

rvList.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrolled(RecyclerView recyclerView, int dx, int dy) {LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();firstVisibleItem = layoutManager.findFirstVisibleItemPosition();lastVisibleItem = layoutManager.findLastVisibleItemPosition();}@Overridepublic void onScrollStateChanged(RecyclerView recyclerView, int newState) {switch (newState) {case RecyclerView.SCROLL_STATE_IDLE://停止滚动/**在这里执行,视频的自动播放与停止*/autoPlayVideo(recyclerView);break;case RecyclerView.SCROLL_STATE_DRAGGING://拖动autoPlayVideo(recyclerView);break;case RecyclerView.SCROLL_STATE_SETTLING://惯性滑动JZVideoPlayer.releaseAllVideos();break;}}});

布局就是一个RecyclerView,就不贴了,下面是Adapter

         urlList = new ArrayList<>();urlList.add("http://image.38.hn/public/attachment/201805/100651/201805181532123423.mp4");urlList.add("http://image.38.hn/public/attachment/201803/100651/201803151735198462.mp4");urlList.add("http://image.38.hn/public/attachment/201803/100651/201803150923220770.mp4");urlList.add("http://image.38.hn/public/attachment/201803/100651/201803150922255785.mp4");urlList.add("http://image.38.hn/public/attachment/201803/100651/201803150920130302.mp4");urlList.add("http://image.38.hn/public/attachment/201803/100651/201803141625005241.mp4");urlList.add("http://image.38.hn/public/attachment/201803/100651/201803141624378522.mp4");urlList.add("http://image.38.hn/public/attachment/201803/100651/201803131546119319.mp4");videoAdapter = new ListVideoAdapter(urlList);rvList.setLayoutManager(new LinearLayoutManager(ListActivity.this));rvList.setAdapter(videoAdapter);

Adapter这里自己做了个封装,可以用原生或者其他封装比较好的,这里就不贴了

  class ListVideoAdapter extends BaseRecAdapter<String, VideoViewHolder> {public ListVideoAdapter(List<String> list) {super(list);}@Overridepublic void onHolder(VideoViewHolder holder, String bean, int position) {holder.mp_video.setUp(bean, JZVideoPlayerStandard.CURRENT_STATE_NORMAL);if (position == 0) {holder.mp_video.startVideo();}Glide.with(context).load(bean).into(holder.mp_video.thumbImageView);holder.tv_title.setText("第" + position + "个视频");}@Overridepublic VideoViewHolder onCreateHolder() {return new VideoViewHolder(getViewByRes(R.layout.item_video));}}public class VideoViewHolder extends BaseRecViewHolder {public View rootView;public MyVideoPlayer mp_video;public TextView tv_title;public VideoViewHolder(View rootView) {super(rootView);this.rootView = rootView;this.mp_video = rootView.findViewById(R.id.mp_video);this.tv_title = rootView.findViewById(R.id.tv_title);}}

布局如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tv_title"android:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:textSize="18sp" /><com.ch.doudemo.widget.MyVideoPlayerandroid:id="@+id/mp_video"android:layout_width="match_parent"android:layout_height="500dp" /></LinearLayout>

这里使用的是 JiaoZiVideoPlayer,其中MyVideoPlayer 是对其做的个性化定制,这里下面再说。

下来就是本篇的核心,通过判断可见项,暂停/播放视频,代码如下

/*** 自动播放*/private void autoPlayVideo(RecyclerView recyclerView) {if (firstVisibleItem == 0 && lastVisibleItem == 0 && recyclerView.getChildAt(0) != null) {MyVideoPlayer videoView = null;if (recyclerView != null && recyclerView.getChildAt(0) != null) {videoView = recyclerView.getChildAt(0).findViewById(R.id.mp_video);}if (videoView != null) {if (videoView.currentState == JZVideoPlayer.CURRENT_STATE_NORMAL || videoView.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) {videoView.startVideo();}}}for (int i = 0; i <= lastVisibleItem; i++) {if (recyclerView == null || recyclerView.getChildAt(i) == null) {return;}MyVideoPlayervideoView = recyclerView.getChildAt(i).findViewById(R.id.mp_video);if (videoView != null) {Rect rect = new Rect();//获取视图本身的可见坐标,把值传入到rect对象中videoView.getLocalVisibleRect(rect);//获取视频的高度int videoHeight = videoView.getHeight();if (rect.top <= 100 && rect.bottom >= videoHeight) {if (videoView.currentState == JZVideoPlayer.CURRENT_STATE_NORMAL || videoView.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) {videoView.startVideo();}return;}JZVideoPlayer.releaseAllVideos();} else {JZVideoPlayer.releaseAllVideos();}}}

顺便说一下,为啥用JiaoZiVideoPlayer,就是因为 JZVideoPlayer.releaseAllVideos();,一句代码就可以暂停所有的播放器,否则自己要实现这个还是比较麻烦的

到这里,大概功能已经实现了,下面说说定制化的功能。需要去掉原播放器的进度条、按钮,点击视频,全屏播放,再次点击取消全屏。

我的做法是添加一个透明度为0的布局,覆盖在播放器上,这样实际上点击的是我们添加的布局

这里有个小技巧,可以粘贴源码中的布局,重要的事情说三遍,不要修改文件名、不要修改文件名、不要修改文件名,找到相关布局,设置android:visibility=“gone”,这样我们的项目中的布局就会替换掉原来的布局。

完整代码如下

jz_layout_standard.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/black"android:descendantFocusability="blocksDescendants"><FrameLayoutandroid:id="@+id/surface_container"android:layout_width="match_parent"android:layout_height="match_parent"></FrameLayout><ImageViewandroid:id="@+id/thumb"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:background="#000000"android:scaleType="fitCenter" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:visibility="gone"><LinearLayoutandroid:id="@+id/layout_bottom"android:layout_width="match_parent"android:layout_height="50dp"android:layout_alignParentBottom="true"android:background="@drawable/jz_bottom_bg"android:gravity="center_vertical"android:orientation="horizontal"android:visibility="invisible"><TextViewandroid:id="@+id/current"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="14dp"android:text="00:00"android:textColor="#ffffff" /><SeekBarandroid:id="@+id/bottom_seek_progress"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:layout_weight="1.0"android:background="@null"android:max="100"android:maxHeight="1dp"android:minHeight="1dp"android:paddingBottom="8dp"android:paddingLeft="12dp"android:paddingRight="12dp"android:paddingTop="8dp"android:progressDrawable="@drawable/jz_bottom_seek_progress"android:thumb="@drawable/jz_bottom_seek_thumb" /><TextViewandroid:id="@+id/total"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="00:00"android:textColor="#ffffff" /><TextViewandroid:id="@+id/clarity"android:layout_width="wrap_content"android:layout_height="wrap_content"android:clickable="true"android:paddingLeft="20dp"android:text="clarity"android:textAlignment="center"android:textColor="#ffffff" /><ImageViewandroid:id="@+id/fullscreen"android:layout_width="52.5dp"android:layout_height="fill_parent"android:paddingLeft="14dp"android:paddingRight="14dp"android:scaleType="centerInside"android:src="@drawable/jz_enlarge" /></LinearLayout></LinearLayout><ProgressBarandroid:id="@+id/bottom_progress"style="?android:attr/progressBarStyleHorizontal"android:layout_width="match_parent"android:layout_height="1.5dp"android:layout_alignParentBottom="true"android:max="100"android:progressDrawable="@drawable/jz_bottom_progress" /><ImageViewandroid:id="@+id/back_tiny"android:layout_width="24dp"android:layout_height="24dp"android:layout_marginLeft="6dp"android:layout_marginTop="6dp"android:background="@drawable/jz_click_back_tiny_selector"android:visibility="gone" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:visibility="gone"><RelativeLayoutandroid:id="@+id/layout_top"android:layout_width="match_parent"android:layout_height="60dp"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:background="@drawable/jz_title_bg"android:gravity="center_vertical"><ImageViewandroid:id="@+id/back"android:layout_width="23dp"android:layout_height="match_parent"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:paddingLeft="12dp"android:paddingStart="12dp"android:scaleType="centerInside"android:src="@drawable/jz_click_back_selector" /><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginEnd="12dp"android:layout_marginLeft="12dp"android:layout_marginRight="12dp"android:layout_marginStart="12dp"android:layout_toEndOf="@+id/back"android:layout_toLeftOf="@+id/battery_time_layout"android:layout_toRightOf="@+id/back"android:ellipsize="end"android:maxLines="2"android:textColor="#ffffff"android:textSize="18sp" /><LinearLayoutandroid:id="@+id/battery_time_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentEnd="true"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginEnd="14dp"android:layout_marginRight="14dp"android:gravity="center_vertical"android:orientation="vertical"><ImageViewandroid:id="@+id/battery_level"android:layout_width="23dp"android:layout_height="10dp"android:layout_gravity="center_horizontal"android:background="@drawable/jz_battery_level_10" /><TextViewandroid:id="@+id/video_current_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:gravity="center_vertical"android:maxLines="1"android:textColor="#ffffffff"android:textSize="12.0sp" /></LinearLayout></RelativeLayout></LinearLayout><ProgressBarandroid:id="@+id/loading"android:layout_width="@dimen/jz_start_button_w_h_normal"android:layout_height="@dimen/jz_start_button_w_h_normal"android:layout_centerHorizontal="true"android:layout_centerVertical="true"android:indeterminateDrawable="@drawable/jz_loading"android:visibility="invisible" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:visibility="gone"><LinearLayoutandroid:id="@+id/start_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentRight="true"android:layout_gravity="center_vertical"><ImageViewandroid:id="@+id/start"android:layout_width="@dimen/jz_start_button_w_h_normal"android:layout_height="@dimen/jz_start_button_w_h_normal"android:src="@drawable/jz_click_play_selector" /></LinearLayout><TextViewandroid:id="@+id/replay_text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/start_layout"android:layout_centerHorizontal="true"android:layout_marginTop="6dp"android:text="@string/replay"android:textColor="#ffffff"android:textSize="12sp"android:visibility="invisible" /><LinearLayoutandroid:id="@+id/retry_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_centerVertical="true"android:gravity="center_horizontal"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/video_loading_faild"android:textColor="@android:color/white"android:textSize="14sp" /><TextViewandroid:id="@+id/retry_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="15dp"android:background="@drawable/retry_bg"android:paddingBottom="4dp"android:paddingLeft="9dp"android:paddingRight="9dp"android:paddingTop="4dp"android:text="@string/click_to_restart"android:textColor="@android:color/white"android:textSize="14sp" /></LinearLayout></LinearLayout><RelativeLayoutandroid:id="@+id/rl_touch_help"android:layout_width="match_parent"android:layout_height="match_parent"android:alpha="0"android:background="@color/cf0f2f7"></RelativeLayout><LinearLayoutandroid:id="@+id/ll_start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_alignParentRight="true"android:padding="15dp"android:visibility="gone"><ImageViewandroid:id="@+id/iv_start"android:layout_width="16dp"android:layout_height="18dp"android:background="@mipmap/stop" /></LinearLayout></RelativeLayout>

还需要实现循环播放,这个比较简单,重写onAutoCompletion方法,当其播放完成时,继续播放即可。

 @Overridepublic void onAutoCompletion() {thumbImageView.setVisibility(View.GONE);if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {onStateAutoComplete();setUp((String) getCurrentUrl(), JZVideoPlayer.SCREEN_WINDOW_FULLSCREEN);} else {super.onAutoCompletion();setUp((String) getCurrentUrl(), JZVideoPlayer.CURRENT_STATE_NORMAL);}//循环播放startVideo();}

到这里,列表播放这个功能已经完成了。

最后,献上完整代码。Github

【Android 进阶】仿抖音系列之列表播放视频(二)相关推荐

  1. 【Android 进阶】仿抖音系列之列表播放视频(三)

    在上一篇[Android 进阶]仿抖音系列之列表播放视频(二)中,我们实现列表播放视频,这一篇我们来对其做些优化. [Android 进阶]仿抖音系列之翻页上下滑切换视频(一) [Android 进阶 ...

  2. 仿抖音上下滑动列表播放短视频解决方案

    因为公司需求需要搞一个像抖音一样的上下滑动的播放列表,寻找了很多方案,最终觉得这个方案还是比较可行的. 1.播放器选择阿里云播放器 阿里云播放器对接文档地址 https://helpcdn.aliyu ...

  3. android 上下翻页素材,【Android 进阶】仿抖音系列之翻页上下滑切换视频(四)...

    前言 大家好,这是这个系列的第四篇,在阅读这篇文章之前,建议可以先看下之前系列的文章,为了节省篇幅,之前详细说过的地方,这里就不再详细描述了: 这一篇,要说实现的是第一篇中的翻页切换视频. 思路 在第 ...

  4. android抖音切换实现,【Android 进阶】仿抖音系列之视频预览和录制(五)

    前言 大家好,在前几篇中,我们通过2种方式实现了仿抖音的翻页切换视频,仿抖音列表播放视频功能:这一篇,我们来说说视频的录制. 主流的视频录制,一般都采用的是FFmpeg 例如 腾讯短视频,由于FFmp ...

  5. 微信小程序仿抖音上下滑动整屏切换视频

    微信小程序仿抖音上下滑动整屏切换视频 使用官网上面的扩展组件 官方使用的方式: 可结合自己业务修改: 使用官网上面的扩展组件 https://developers.weixin.qq.com/mini ...

  6. Android高仿抖音滚动聊天,Android仿抖音列表效果

    本文实例为大家分享了Android仿抖音列表效果的具体代码,供大家参考,具体内容如下 当下抖音非常火热,是不是也很心动做一个类似的app吗? 那我们就用RecyclerView实现这个功能吧,关于内存 ...

  7. android 高仿抖音界面,2018-11-05 Android 仿抖音选择封面自定义控件

    写在前头,抖音里面很多控件,效果很不错,但是,Android 跟iOS的表现形式以及实现方式,都是有区别的,这里实现Android左右拖拉控件进行视频封面选择. public class Choice ...

  8. 仿抖音写上下滑动切换视频

    公司小程序要做个仿抖音上下切换视频的效果,一开始想用swiper,有资料说多了会卡.原因是video标签太多的原因,查看资料有只是用一个video标签的,滑动时切换src即可 全部代码 <tem ...

  9. Android高仿抖音照片电影功能

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 PhotoMovie(https://github.com/yellowcath/PhotoMovie)可轻松实现类似抖音.微视.美 ...

最新文章

  1. 旷视发布《人工智能应用准则》,倡导AI技术健康可持续发展
  2. 配置Windows server 2008 R2脱机加入域功能
  3. Redis 基本操作
  4. python批量识别图中文字自动命名_python实现批量命名照片
  5. How to adjust OOM score for a process?
  6. 存储芯片在智能化产业链中扮演的角色将更加重要
  7. Qt实践|HTTPS知识点-SSL socket获取百度首页
  8. 【Flink】Flink 流API 和 Table 以及 SQL API是否可以共存
  9. 【微信小程序】组件间通信与事件-获取子组件的实例对象
  10. 程序员修炼之道 pdf_程序员修炼之道-注重实效
  11. cocos creator 数组_5Cocos Creator 脚本简介
  12. 订单管理系统哪种简单好用?
  13. 20145322何志威 《信息安全系统设计基础》第2周学习总结
  14. iOS获取屏幕尺寸的方法
  15. 怎么操作信任另一台计算机,电脑上怎么设置信任软件
  16. jquery 报错提示Uncaught TypeError: $ is not a function
  17. 使用正则表达式进行身份证号匹配
  18. idea2018激活码
  19. docker-compose docker容器编排插件
  20. 2021年安全员-A证(山东省-2021版)最新解析及安全员-A证(山东省-2021版)模拟试题

热门文章

  1. 1070 结绳 (25 分) (C++)
  2. chrome 如何设置Google英文搜索
  3. ECharts 地图使用
  4. H3C S7500E V7 系列交换机产品及维护介绍--优化
  5. 迈克菲实验室报告揭示全新的移动应用合谋威胁
  6. 蔻驰和mk哪个更大牌_mk和蔻驰是一个档次吗?
  7. 在C语言中使用英文字符
  8. Pandas set_index 用法
  9. Java 定时任务配置文件
  10. 5月不良与垃圾信息举报:垃圾邮件8254件次 增5.8%