近期遇到一个需求是做类似微博中视频在WiFi状态下自动播放,故写了一个简单的demo。重点代码都会贴出来,一些细节,项目中加了demo上并没有添加(例如:判断是否为WiFi状态)在这里说明一下。
需求:
1. 当视频item中视频部分露出超过1/3时,视频开始自动播放,当视频部分露出不足1/3时,视频停止播放,当下次满足自动播放要求时,从头播放。
2.当一屏中有2个满足以上自动播放规则的视频item时,一直轮播符合要求的第一个视频卡片
3.当下滑将已暂停的视频item视频部分超过1/3划回当前屏幕时,则该视频开始从头自动播放,之前正在播放的暂停播放且回到初始item样式
实现思路:
思路一:实例化一个视频播放器备用,实现滑动监听,判断符合播放标准item,将已经实例化的播放器动态add到该item指定展示位置进行播放,当该item不满足播放要求将其remove出去并将播放器置于初始状态待下次使用,然后继续判断符合要求item进行add...
思路二:将播放器置于item的布局中将其隐藏,实现滑动监听,判断符合播放位置,将其set给adapter并刷新,在onBindViewHolder方法中判断position是否等于播放位置,如果等于显示播放器并播放,不等于判断是否处于播放状态将其停止播放并释放资源以及隐藏。
思路一相对更加简单灵活并且性能好,然鹅...我是按照思路二做的。下面附上代码,其中有部分注释。
public class VideoListActivity extends BaseActivity {
@InjectView(R.id.lv_video)
RecyclerView lvVideo;
private List<String> data;
private MyAdapter adapter;
private LinearLayoutManager mLayoutManager;
int playPosition = 0;
@Override
public void onClick(View v) {
}
@Override
public void bindLayout() {
setContentView(R.layout.activity_video_list);
ButterKnife.inject(this);
}
@Override
public void initView() {
data = new ArrayList<>();
for (int i = 0; i < 20; i++) {
data.add("http://crk.momocdn.com/mv/DD/E6/DDE62798-C8F1-4526-ACC1-E2240328B12E20180406_h264.mp4");
}
mLayoutManager = new LinearLayoutManager(this);
//2 为RecyclerView创建布局管理器,这里使用的是LinearLayoutManager,表示里面的Item排列是线性排列
lvVideo.setLayoutManager(mLayoutManager);
adapter = new MyAdapter();
lvVideo.setAdapter(adapter);
}
@Override
public void setListener() {
}
@Override
public void doBusiness() {
lvVideo.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
recyclerView.getBaseline();
//direction为 -1 表示手指向下滑动(屏幕向上滑动), 1 表示手指向上滑动(屏幕向下滑动)。
if (mLayoutManager != null) {
int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();//得到显示屏内的第一个list的位置数position
View firstView = mLayoutManager.findViewByPosition(firstVisibleItem);
if (null != firstView) {
if (dy > 0) {
if (firstView.getHeight() + firstView.getTop() <= firstView.getHeight() / 3) {
//video stop or play second
if (mLayoutManager.getChildCount() < 2) {
return;
}
if (playPosition == firstVisibleItem + 1) {
return;
}
playPosition = firstVisibleItem + 1;
adapter.setPlay(playPosition);
} else {
if (playPosition == firstVisibleItem) {
return;
}
playPosition = firstVisibleItem;
adapter.setPlay(playPosition);
}
}
if (dy < 0) {
if (firstView.getHeight() + firstView.getTop() >= firstView.getHeight() * 2 / 3) {
//video stop or play second
if (mLayoutManager.getChildCount() < 2) {
return;
}
if (playPosition == firstVisibleItem) {
return;
}
playPosition = firstVisibleItem;
adapter.setPlay(playPosition);
} else {
if (playPosition == firstVisibleItem + 1) {
return;
}
playPosition = firstVisibleItem + 1;
adapter.setPlay(playPosition);
}
}
}
}
}
});
}
class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private int play = 0;
public void setPlay(int play) {
this.play = play;
notifyDataSetChanged();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//加载布局文件
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_videolist, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(final ViewHolder viewHolder, int position) {
//将数据填充到具体的view中
viewHolder.iv.setVisibility(View.VISIBLE);
viewHolder.ijkPlayer.release();
if (play == position) {
viewHolder.ijkPlayer.setVisibility(View.VISIBLE);
viewHolder.ijkPlayer.setVideoPath(data.get(position));
viewHolder.iv.setVisibility(View.GONE);
LogManager.e("======" + position);
} else {
viewHolder.iv.setVisibility(View.VISIBLE);
viewHolder.ijkPlayer.setVisibility(View.GONE);
viewHolder.ijkPlayer.release();
}
viewHolder.tv.setText("video" + position);
}
@Override
public int getItemCount() {
return data.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView tv;
ImageView iv;
VideoPlayerIJK ijkPlayer;
public ViewHolder(View itemView) {
super(itemView);
ijkPlayer = (VideoPlayerIJK) itemView.findViewById(R.id.sf_videoview);
tv = (TextView) itemView.findViewById(R.id.tv);
iv = (ImageView) itemView.findViewById(R.id.iv);
}
}
}
}
总结:
遇到了一个很鸡肋的问题,自动播放了前几个后面的就不播放了问题就出在如下代码
1.View firstView = mLayoutManager.getChildAt(firstVisibleItem); 2.View firstView = mLayoutManager.findViewByPosition(firstVisibleItem);
1是开始出问题的代码,打了日志才发现,由于RecyclerView的复用机制而1方法只能获得复用的item因此无法获得准确的高度与位置后面被复用的就无法满足播放标准了。
经过网上各种查找最后在源码中找到了2这个讨人喜爱的方法最终问题解决。
在项目中使用思路没错可惜项目本身有坑,今天解决一天终于over了,蟹蟹自己。