作者 | DK_BurNIng 地址 | juejin.im/post/5e5f4a5be51d4526cb162775
阅读本文解决什么问题?
何时播视频最合适?
-
就如同我们平时做listview或者RecyclerView列表页优化的时候,考虑到图片的加载涉及到io,还有少部分的decode操作,所以我们都会在滑动停止或者是滑动速度变低的时候才加载图片,降低cpu的负载和内存抖动来达到提高页面滑动流畅性的目的,所以播视频也是一样的,在列表页停止滑动的时候才播放视频是可以大大提高页面流畅性的。 -
即使你的播放器是自研的,但是依旧不建议在列表页滑动的时候进行视频播放,考虑如下场景:A视频正在播放, 此时进行滑动,B视频到了播放区域开始播B视频,此时A从播视频的状态切到停止播放视频的视频封面图状态,B 视频从视频封面图状态切到播放状态(甚至还有黑底的loading的状态),可以想象滑动速度一旦变快,视觉上的效果 就会非常难受,那种一顿顿的效果,因为你列表页中的item几乎全在同一时刻切换图片状态。
所以要在哪个地方开始播视频?


如何合理规划播视频的区域?
case SCROLL_STATE_IDLE:
//取第一个展示出来的item
int firstPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
//最后一个展示出来的item
int lastPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
//开始遍历
for (int i = firstPosition; i <= lastPosition; i++) {
//取出这个列表页中的item
View itemView = recyclerView.getLayoutManager().findViewByPosition(i);
//一定要先判空 因为有时上面这个函数真的会返回null
//然后接着判断 是不是有视频播放组件 比如有的列表页除了有视频item还有纯图片的item
//所以要判定这个条件
if (itemView != null && itemView.findViewById(R.id.video_player) != null) {
VideoPlayer videoPlayer = itemView.findViewById(R.id.video_player);
if (isCanBePlayedByRect(videoPlayer)) {
safePlayVideoMethod(videoPlayer);
break;
}
}
}
private boolean isCanBePlayedByRect(VideoPlayer videoPlayer) {
Rect rect = new Rect();
//这里就可以取出来视频播放区域的坐标轴了
videoPlayer.getLocalVisibleRect(rect);
int videoHeight = videoPlayer.getHeight();
//符合这个条件就意味着 整个视频播放区域 都是完整的呈现在视频中的
final boolean playFlag = (rect.top == 0 && rect.bottom == videoHeight)
return playFlag;
}


-
如果这个tab以后高度修改了,你能保证每次别人的修改你都知道么? -
除了有底部tab还有虚拟键的高度啊,这样一算 不是太复杂了么?
if (mTabWidget != null && MAIN_PAGE_BOTTOM_TAB_RECT_TOP == 0) {
Rect rect = new Rect();
//注意 我们这里 使用的是getGlobalVisibleRect 而不是getLocal了
//区别就是 global取得就是 针对全屏幕的坐标轴
mTabWidget.getGlobalVisibleRect(rect);
MAIN_PAGE_BOTTOM_TAB_RECT_TOP = rect.top;
}
private boolean isCanBePlayedByRect(VideoPlayer videoPlayer) {
Rect rect = new Rect();
videoPlayer.getLocalVisibleRect(rect);
Rect gRect = new Rect();
//把视频view的全局 bottom坐标 也取出来 与tab的top坐标做对比
videoPlayer.getGlobalVisibleRect(gRect);
int videoHeight = videoPlayer.getHeight();
final boolean playFlag = (rect.top == 0 && rect.bottom == videoHeight && gRect.bottom < MAIN_PAGE_BOTTOM_TAB_RECT_TOP);
return playFlag;
}
什么时候停止播放?

这个回调 会简单一些?
int position = 0;
if (dy > 0) {
//dy>0 代表 item 从下往上 被划出屏幕的 所以我们只需要判定最上面一个可视的item即可
position = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition();
} else if (dy < 0) {
//dy>0 代表 item 从上往下 被划出屏幕的 所以我们只需要判定最下面一个可视的item即可
position = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findLastVisibleItemPosition();
}
View itemView = mRecyclerView.getLayoutManager().findViewByPosition(position);
if (itemView != null) {
VideoPlayer videoPlayer = itemView.findViewById(R.id.video_player);
if (videoPlayer != null) {
Rect rect = new Rect();
Rect gRect = new Rect();
vivoSpaceVideoPlayer.getLocalVisibleRect(rect);
vivoSpaceVideoPlayer.getGlobalVisibleRect(gRect);
//item 从下往上划出屏幕 的判定条件
final boolean stopFlagForDownToUp = (dy > 0 && rect.bottom - rect.top <= STOP_FLAG_PX_VALUE);
//item 从上往下划出屏幕的 判定条件 ----有底部tab
final boolean stopFlagForUptoDown1 = (dy < 0 && gRect.top > (MAIN_PAGE_BOTTOM_TAB_RECT_TOP - STOP_FLAG_PX_VALUE));
//item 从上往下划出屏幕的 判定条件 ----没有底部tab
final boolean stopFlagForUptoDown2 = (dy < 0 && rect.top != 0);
if (stopFlagForDownToUp || stopFlagForUptoDownHasParent || stopFlagForUptoDownNoParent) {
videoPlayer.release();
}
}
}
//定义个阈值 停止播放判定使用
private static final int STOP_FLAG_PX_VALUE = 5;
怎么确保列表页第一次被渲染的时候就自动播放?
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if (!mRvInitFlag) {
playFirstVideoView();
mRvInitFlag = true;
return;
}
private void playFirstVideoView() {
VLog.d(TAG, "method in playFirstVideoView");
if (mRecyclerView.getLayoutManager() != null) {
//只有是 视频 才有意义,如果都不是视频 那没有任何意义
int firstPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition();
int lastPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findLastVisibleItemPosition();
for (int i = firstPosition; i <= lastPosition; i++) {
// 如果 i<0 则直接跳过 因为毫无意义
if (i < 0) {
continue;
}
View itemView = mRecyclerView.getLayoutManager().findViewByPosition(i);
if (itemView != null && itemView.findViewById(R.id.video_player) != null) {
VideoPlayer videoPlayer = itemView.findViewById(R.id.video_player);
Rect rect = new Rect();
Rect gRect = new Rect();
videoPlayer.getLocalVisibleRect(rect);
videoPlayer.getGlobalVisibleRect(gRect);
int videoHeight = videoPlayer.getHeight();
//只要第一个元素 可视区域是完整的,那么就直接给他播放
if ((rect.bottom - rect.top) == videoHeight && gRect.bottom < MAIN_PAGE_BOTTOM_TAB_RECT_TOP && gRect.bottom > 0) {
safePlayVideoMethod(videoPlayer);
//既然找到了 那么就直接播放 不要再管其他的了
break;
}
}
}
}
原文始发于微信公众号(互联网程序员):Android列表页播视频看这一篇就足够了
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/24123.html