欢迎Follow我的GitHub, 关注我的CSDN.

本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html

在应用的信息流中, 用户会分享视频, 连续展示, 这就需要处理视频滚动播放. 然而, 在列表视图(RecyclerView)中使用MediaPlayer播放视频时, 会产生一些问题, 即无法同步控制视频的播放和停止. 使用控件库可以解决这一问题.

滚动播放功能: 在页面中, 判断视频的可视比例, 最大视频项开始播放, 其余视频项关闭, 滚动中自动控制切换视频状态. 让我们来看看如何实现这一功能.

本文示例的Github下载地址.

使用的视频管理库.

    // 视频播放库compile 'com.github.danylovolokh:video-player-manager:0.2.0'compile 'com.github.danylovolokh:list-visibility-utils:0.2.0'

效果


1. 基本配置

依赖注入, 图片加载, 和视频播放.

    compile 'com.jakewharton:butterknife:7.0.1' // 依赖注入compile 'com.squareup.picasso:picasso:2.5.2' // 图片加载// 视频播放库compile 'com.github.danylovolokh:video-player-manager:0.2.0'compile 'com.github.danylovolokh:list-visibility-utils:0.2.0'

首页跳转到Fragment, 可以选择本地视频或者网络视频两种方式.

public class MainActivity extends AppCompatActivity {public static final int LOCAL = 0; // 本地public static final int ONLINE = 1; // 在线@Bind(R.id.main_t_toolbar) Toolbar mTToolbar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);mTToolbar.setTitle("列表");setSupportActionBar(mTToolbar);if (savedInstanceState == null) {getSupportFragmentManager().beginTransaction().replace(R.id.main_fl_container, VideoListFragment.newInstance(LOCAL)).commit();}}@Override public boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.menu_main, menu);return true;}@Override public boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.enable_local_video:if (!item.isChecked()) {getSupportFragmentManager().beginTransaction().replace(R.id.main_fl_container, VideoListFragment.newInstance(LOCAL)).commit();}break;case R.id.enable_online_video:if (!item.isChecked()) {getSupportFragmentManager().beginTransaction().replace(R.id.main_fl_container, VideoListFragment.newInstance(ONLINE)).commit();}break;}item.setChecked(!item.isChecked());return true;}
}

使用Fragment的工厂模式添加参数. 通过菜单选项可以切换模式.
item.setChecked(!item.isChecked());改变切换状态


2. 视频列表

设置Video列表的Adapter, 添加滚动状态监听, 实现动态切换视频.
ItemsPositionGetter判断显示百分比, 提供回调控制视频状态.
通过Fragment的设置参数, 判断播放使用本地视频还是网络视频.

    @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);Bundle args = getArguments();if (args != null) {// 设置类型if (args.getInt(VIDEO_TYPE_ARG) == MainActivity.LOCAL) {initLocalVideoList();} else {initOnlineVideoList();}} else {initLocalVideoList();}mRvList.setHasFixedSize(true);mLayoutManager = new LinearLayoutManager(getActivity());mRvList.setLayoutManager(mLayoutManager);VideoListAdapter adapter = new VideoListAdapter(mList);mRvList.setAdapter(adapter);// 获取Item的位置mItemsPositionGetter = new RecyclerViewItemPositionGetter(mLayoutManager, mRvList);mRvList.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrollStateChanged(RecyclerView recyclerView, int scrollState) {mScrollState = scrollState;if (scrollState == RecyclerView.SCROLL_STATE_IDLE && !mList.isEmpty()) {mVisibilityCalculator.onScrollStateIdle(mItemsPositionGetter,mLayoutManager.findFirstVisibleItemPosition(),mLayoutManager.findLastVisibleItemPosition());}}@Overridepublic void onScrolled(RecyclerView recyclerView, int dx, int dy) {if (!mList.isEmpty()) {mVisibilityCalculator.onScroll(mItemsPositionGetter,mLayoutManager.findFirstVisibleItemPosition(),mLayoutManager.findLastVisibleItemPosition() -mLayoutManager.findFirstVisibleItemPosition() + 1,mScrollState);}}});}

视频列表主要是监听出现百分比, 动态切换视频.

3. 适配器

适配器和ViewHolder. 绑定视频元素, 播放监听控制覆盖层的显示与隐藏.

/*** 视频列表的适配器* <p/>* Created by wangchenlong on 16/1/27.*/
public class VideoListAdapter extends RecyclerView.Adapter<VideoListAdapter.VideoViewHolder> {private final List<VideoListItem> mList; // 视频项列表// 构造器public VideoListAdapter(List<VideoListItem> list) {mList = list;}@Overridepublic VideoListAdapter.VideoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_video, parent, false);// 必须要设置Tag, 否则无法显示VideoListAdapter.VideoViewHolder holder = new VideoListAdapter.VideoViewHolder(view);view.setTag(holder);return new VideoListAdapter.VideoViewHolder(view);}@Overridepublic void onBindViewHolder(final VideoListAdapter.VideoViewHolder holder, int position) {VideoListItem videoItem = mList.get(position);holder.bindTo(videoItem);}@Override public int getItemCount() {return mList.size();}public static class VideoViewHolder extends RecyclerView.ViewHolder {@Bind(R.id.item_video_vpv_player) VideoPlayerView mVpvPlayer; // 播放控件@Bind(R.id.item_video_iv_cover) ImageView mIvCover; // 覆盖层@Bind(R.id.item_video_tv_title) TextView mTvTitle; // 标题@Bind(R.id.item_video_tv_percents) TextView mTvPercents; // 百分比private Context mContext;private MediaPlayerWrapper.MainThreadMediaPlayerListener mPlayerListener;public VideoViewHolder(View itemView) {super(itemView);ButterKnife.bind(this, itemView);mContext = itemView.getContext().getApplicationContext();mPlayerListener = new MediaPlayerWrapper.MainThreadMediaPlayerListener() {@Overridepublic void onVideoSizeChangedMainThread(int width, int height) {}@Overridepublic void onVideoPreparedMainThread() {// 视频播放隐藏前图mIvCover.setVisibility(View.INVISIBLE);}@Overridepublic void onVideoCompletionMainThread() {}@Overridepublic void onErrorMainThread(int what, int extra) {}@Overridepublic void onBufferingUpdateMainThread(int percent) {}@Overridepublic void onVideoStoppedMainThread() {// 视频暂停显示前图mIvCover.setVisibility(View.VISIBLE);}};mVpvPlayer.addMediaPlayerListener(mPlayerListener);}public void bindTo(VideoListItem vli) {mTvTitle.setText(vli.getTitle());mIvCover.setVisibility(View.VISIBLE);Picasso.with(mContext).load(vli.getImageResource()).into(mIvCover);}// 返回播放器public VideoPlayerView getVpvPlayer() {return mVpvPlayer;}// 返回百分比public TextView getTvPercents() {return mTvPercents;}}
}

注意, 在onCreateViewHolder中, 在View的Tag中绑定所属的ViewHolder. 视频项类VideoListItem会在Tag中提取ViewHolder, 设置显示效果.


4. 视频项

通过ItemsPositionGetter类提供的接口, 返回显示比例, 根据显示区域的大小, 控制视频播放的启动还是停止, 实现自动切换视频状态功能.

public abstract class VideoListItem implements VideoItem, ListItem {private final Rect mCurrentViewRect; // 当前视图的方框private final VideoPlayerManager<MetaData> mVideoPlayerManager; // 视频播放管理器private final String mTitle; // 标题@DrawableRes private final int mImageResource; // 图片资源// 构造器, 输入视频播放管理器public VideoListItem(VideoPlayerManager<MetaData> videoPlayerManager,String title,@DrawableRes int imageResource) {mVideoPlayerManager = videoPlayerManager;mTitle = title;mImageResource = imageResource;mCurrentViewRect = new Rect();}// 视频项的标题public String getTitle() {return mTitle;}// 视频项的背景public int getImageResource() {return mImageResource;}// 显示可视的百分比程度@Override public int getVisibilityPercents(View view) {int percents = 100;view.getLocalVisibleRect(mCurrentViewRect);int height = view.getHeight();if (viewIsPartiallyHiddenTop()) {percents = (height - mCurrentViewRect.top) * 100 / height;} else if (viewIsPartiallyHiddenBottom(height)) {percents = mCurrentViewRect.bottom * 100 / height;}// 设置百分比setVisibilityPercentsText(view, percents);return percents;}@Override public void setActive(View newActiveView, int newActiveViewPosition) {VideoListAdapter.VideoViewHolder viewHolder =(VideoListAdapter.VideoViewHolder) newActiveView.getTag();playNewVideo(new CurrentItemMetaData(newActiveViewPosition, newActiveView),viewHolder.getVpvPlayer(), mVideoPlayerManager);}@Override public void deactivate(View currentView, int position) {stopPlayback(mVideoPlayerManager);}@Override public void stopPlayback(VideoPlayerManager videoPlayerManager) {videoPlayerManager.stopAnyPlayback();}// 显示百分比private void setVisibilityPercentsText(View currentView, int percents) {VideoListAdapter.VideoViewHolder vh =(VideoListAdapter.VideoViewHolder) currentView.getTag();String percentsText = "可视百分比: " + String.valueOf(percents);vh.getTvPercents().setText(percentsText);}// 顶部出现private boolean viewIsPartiallyHiddenTop() {return mCurrentViewRect.top > 0;}// 底部出现private boolean viewIsPartiallyHiddenBottom(int height) {return mCurrentViewRect.bottom > 0 && mCurrentViewRect.bottom < height;}
}

动画效果

虽然使用视频播放的管理器, 但播放功能还是需要注意一些细节. 毕竟视频播放是个比较复杂的过程, 需要考虑的很多事情.

OK, that’s all! Enjoy it!

炫丽的朋友圈视频滚动播放功能相关推荐

  1. android朋友圈自动播放,微信安卓7.0.5内测新版功能 朋友圈视频自动播放关闭设置...

    微信安卓7.0.5内测新版功能.微信又迎来了新的版本,虽然这次是小版本的更新,不过带来的新功能却挺好用的,一起来看看吧.这个版本的微信尚处于内测阶段想要尝鲜的用户还需要等等. 微信视频动态增强 图片秒 ...

  2. 微信朋友圈视频变长从6秒增加为10秒

    微信iOS版本发布更新了,"大视频"允许拍摄更长时间的视频:从原来的6秒增加为10秒.新版微信还支持从相册里分享视频到朋友圈,不再强制要求只有直接拍摄的"小视频" ...

  3. android bmob 朋友圈,仿微信朋友圈视频效果 – MVideo

    MVideo 仿微信朋友圈视频效果,可以拖拽及缩放,视频查看,基于ijkplayer. Demo 入门 Step 1:在buil文件中添加JitPack仓库: allprojects { reposi ...

  4. 怎样屏蔽微信朋友圈视频?局域网如何禁止员工看朋友圈视频?

    上班时间刷刷朋友圈,一眨眼半小时就过去了.不但会影响工作效率,而且朋友圈的视频会占用大量的带宽.所以对企业管理人员来说,很多时候需要禁止员工在工作时段刷朋友圈.但是行政手段要和技术手段配合,才可以发挥 ...

  5. 微信朋友圈视频怎么编辑比较好

    微信朋友圈可以从手机相册中选择视频来分享了,但是只能是时长为10秒以下的,这也意味着超过10秒的视频都必须经过编辑才能发布,那么问题来了,朋友圈视频该怎么编辑?编辑功能很简单,你可以分别从视频的开始和 ...

  6. 微信又双叒更新啦!新增朋友圈视频动态封面,还有这些实用的功能!

    嗨,大家好呀,我是柚妹!微信的更新上,安卓端似乎总是比iOS端慢半拍,比如微信8.0大版本,不仅安卓端晚了好几天,iOS端先后发布了两个升级版之后,安卓端的第一次升级才姗姗来迟! 就在昨天,微信安卓端 ...

  7. android实现朋友圈播放视频,实现类似朋友圈视频的滚动播放功能

    欢迎Follow我的GitHub, 关注我的简书. 其余参考Android目录. 效果 Android 在应用的信息流中, 用户会分享视频, 连续展示, 这就需要处理视频滚动播放. 然而, 在列表视图 ...

  8. iOS完美实现微信朋友圈视频截取

    点击上方"iOS开发",选择"置顶公众号" 关键时刻,第一时间送达! 先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明 ...

  9. android微信朋友圈视频无法播放,微信朋友圈不能分享手机视频怎么回事?微信朋友圈大视频功能安卓不能用吗?...

    微信朋友圈不能分享手机视频怎么回事?微信朋友圈大视频功能安卓不能用吗?最近微信更新,用户可以进行分享自己手机里的视频,这一举措受到很多人的喜欢.那么微信朋友圈不能分享手机视频怎么回事?微信朋友圈大视频 ...

最新文章

  1. ASP.NET 2.0 中配合 Master Page 使用的优化 CSS 模型
  2. React.js再探(四)
  3. 无连接可靠传输_尽力传输是什么 尽力传输原理介绍【图文】
  4. 容器资源可视化隔离的实现方法
  5. document.getelementbyid().value与innerHTML使用场景对比,别再搞错了兄嘚
  6. AbiWord 中Piece Table 数据结构的实现
  7. 泛微协同商务系统_【泛微云办公平台eteams_泛微在线oa协同办公系统】
  8. 编译x86_64老是不过,iphone模拟器debug不了解决方法
  9. 微信小程序 环形进度条_微信小程序实现圆形进度条
  10. 「Adobe国际认证」Adobe Photoshop,如何裁剪并拉直照片?
  11. 怎么在本地运行java项目,eclipse怎么运行java web项目?
  12. 02 stata入门【计量经济学及stata应用】
  13. Linux环境下几种常用的文件系统
  14. 对于计算机专业的个人理解
  15. 【数据分析】——分析方法
  16. HiPER月光网吧宽带安全网关接入解决方案(转)
  17. 说一说JS数据类型有哪些
  18. docker 基础知识分享ppt
  19. 行业研究报告-全球与中国吊钩市场现状及未来发展趋势
  20. 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1

热门文章

  1. 全新版大学英语综合教程3(课后答案)完全版
  2. zotero翻译插件PDF Translate下载安装配置
  3. 多边形内角和c语言编程,多边形的内角和与外角和同步练习题
  4. Unity学习之工厂模式
  5. 数据库存储图片路径并显示到前端
  6. 上课睡觉-数论+枚举
  7. MAC电脑上有哪些好用的小说阅读器?
  8. 类名.class的含义
  9. Android ROOT System权限 设备管理器
  10. MongoDB Compass 操作MongoDB数据库