ViewPager2实现视频与图片混合播放
最近公司需要完成一个视频与图片混合播放的功能,在网上搜索的半天,发现要么有问题,要么就是不达标,有的经过测试还有问题,因此我也是发了几天想想了自己做了一个
下面来看看我自己做的
先说说需求:需要实现图片轮播,且轮播时,视频需要暂停,过视频播放完成后,需要继续轮播,同时还要有连续播放,不能回头重播的效果,并且还需要在没有网络的情况下继续播放,这就需要进行缓存。
第一步添加权限
<uses-permission android:name="android.permission.INTERNET" />
<!--用于写入缓存数据到扩展存储卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
第二步使用包,视频包最好是下载下来,可以修改,并且完成自己需求
implementation "androidx.viewpager2:viewpager2:1.0.0"
//视频缓存
implementation 'com.danikula:videocache:2.7.1'
//此引用包最好下载下来方便修改
implementation 'com.github.xiaoyanger0825:NiceVieoPlayer:v2.2'
第三步就开始自己的实现
注意点:
1.需要使用 Integer.MAX_VALUE来完成不重复的轮播
2.需要使用Handle来完成轮询
废话不多说先上代码
FiveActivity.java
public class FiveActivity extends AppCompatActivity {
private ViewPager2 mViewPager;
private ArrayList<DataBean> testDataVideo;
private Handler mHandler = new Handler();
private SwishTask mTask;
private LinearLayout ll_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_five);
mViewPager = findViewById(R.id.viewPager2);
ll_view = findViewById(R.id.ll_view);
mViewPager.setOffscreenPageLimit(1);
testDataVideo = DataBean.getTestDataVideo();
int pos = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % testDataVideo.size());
mViewPager.setCurrentItem(pos);//可以实现左右无限轮播
mViewPager.setAdapter(new MyAdapter(this, testDataVideo));
if (mTask == null) {
mTask = new SwishTask();
}
mTask.start();
// 给容器添加点
for (int i = 0; i < testDataVideo.size(); i++) {
ImageView iv = new ImageView(this);
iv.setImageResource(R.mipmap.indicator_normal);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
if (i == 0) {
// 设置默认
iv.setImageResource(R.mipmap.indicator_selected);
} else {
params.leftMargin = dp2px(6);// px
params.bottomMargin = dp2px(6);
}
ll_view.addView(iv, params);
}
//触摸事件暂时无法使用
mViewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
System.out.println("result-->onTouch");
return false;
}
});
mViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
@Override
public void onPageSelected(int position) {
int pos = position % testDataVideo.size();
System.out.println("result-->onPageSelected:" + pos);
// 改变点选中
int childCount = ll_view.getChildCount();
System.out.println("result-->childCount:" + childCount);
for (int i = 0; i < childCount; i++) {
ImageView iv = (ImageView) ll_view.getChildAt(i);
iv.setImageResource(pos == i ? R.mipmap.indicator_selected : R.mipmap.indicator_normal);
}
}
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
}
/**
* 像素转dp
*
* @param px
* @return
*/
public int px2dp(int px) {
// px = dp * (dpi / 160)
// dp = px * 160 / dpi
DisplayMetrics metrics = getResources().getDisplayMetrics();
int dpi = metrics.densityDpi;
return (int) (px * 160f / dpi + 0.5f);
}
/**
* dp转px
*
* @param dp
* @return
*/
public int dp2px(int dp) {
// px = dp * (dpi / 160)
DisplayMetrics metrics = getResources().getDisplayMetrics();
int dpi = metrics.densityDpi;
return (int) (dp * (dpi / 160f) + 0.5f);
}
public class MyAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private Context mContext;
private ArrayList<DataBean> mData;
public MyAdapter(Context context, ArrayList<DataBean> list) {
this.mContext = context;
this.mData = list;
}
@NonNull
@Override
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 1) {
View inflate = LayoutInflater.from(mContext).inflate(R.layout.activity_demo2, parent, false);
BaseViewHolder holder = new PicViewHolder(inflate, 1, mTask);
return holder;
} else if (viewType == 2) {
View view = LayoutInflater.from(mContext).inflate(R.layout.activity_demo3, parent, false);
BaseViewHolder videoHolder = new VideoHolder(view, 2, mTask,mContext);
return videoHolder;
} else {
return null;
}
}
@Override
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
position = position % testDataVideo.size();
int type = mData.get(position).viewType;
if (type == 1) {
PicViewHolder picViewHolder = holder.getPicViewHolder();
if (picViewHolder != null) {
picViewHolder.setPicData(mData.get(position));
}
} else if (type == 2) {
VideoHolder videoHolder = holder.getVideoHolder();
if (videoHolder != null) {
NiceVideoPlayer niceVideoPlayer = videoHolder.video_player;
if (niceVideoPlayer == NiceVideoPlayerManager.instance().getCurrentNiceVideoPlayer()) {
NiceVideoPlayerManager.instance().releaseNiceVideoPlayer();
}
videoHolder.bindData(mData.get(position));
videoHolder.setData();
}
}
}
@Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
@Override
public int getItemViewType(int position) {
position = position % testDataVideo.size();
return mData.get(position).viewType;
}
}
public class SwishTask implements Runnable {
private boolean flag=false;
@Override
public void run() {
int item = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(++item);
item = item % testDataVideo.size();
DataBean dataBean = testDataVideo.get(item);
if (dataBean.viewType==2){
stop();
} else {
mHandler.postDelayed(this, 3000);
}
}
public void start() {
stop();
int item = mViewPager.getCurrentItem();
item = item % testDataVideo.size();
DataBean dataBean = testDataVideo.get(item);
if (dataBean.viewType==2 && flag==false && item<1 ){
//如果是视频,并且是第一次进来,同时还是视频在第一位时
flag=true;
} else {
System.out.println("result-->start");
mHandler.postDelayed(this, 3000);
}
}
public void stop() {
System.out.println("result-->stop");
mHandler.removeCallbacks(this);
mHandler.removeCallbacksAndMessages(null);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onStop() {
super.onStop();
NiceVideoPlayerManager.instance().releaseNiceVideoPlayer();
}
@Override
public void onBackPressed() {
if (NiceVideoPlayerManager.instance().onBackPressd()) return;
super.onBackPressed();
}
}
activity_five.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">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
android:layout_width="match_parent"
android:layout_height="180dp" />
<LinearLayout
android:id="@+id/ll_view"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_alignBottom="@+id/viewPager2"
android:orientation="horizontal"
android:gravity="center_horizontal"/>
</RelativeLayout>
BaseViewHolder.java
public class BaseViewHolder extends RecyclerView.ViewHolder{
public BaseViewHolder(@NonNull View itemView,int type) {
super(itemView);
}
public VideoHolder getVideoHolder(){
return (VideoHolder)this;
}
public PicViewHolder getPicViewHolder(){
return (PicViewHolder)this;
}
}
PicViewHolder.java
public class PicViewHolder extends BaseViewHolder {
private ImageView iv_Image;
public PicViewHolder(@NonNull View itemView,int type,FiveActivity.SwishTask task) {
super(itemView,type);
iv_Image = itemView.findViewById(R.id.iv_Image);
}
public void setPicData(DataBean bean){
iv_Image.setImageResource(bean.imageRes);
}
}
activity_demo2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_Image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
VideoHolder.java
public class VideoHolder extends BaseViewHolder implements TxVideoPlayerController.CompletLinstener{
public NiceVideoPlayer video_player;
public TxVideoPlayerController mController;
private FiveActivity.SwishTask mTask;
private HttpProxyCacheServer proxy;
public VideoHolder(@NonNull View itemView, int type, FiveActivity.SwishTask task, Context mContext) {
super(itemView, type);
this.mTask = task;
video_player = itemView.findViewById(R.id.video_player);
mController= new TxVideoPlayerController(mContext);
proxy = BaseApplication.getProxy(mContext);
video_player.setController(mController);
}
public void bindData(DataBean video) {
mController.setTitle(video.title);
String proxyUrl = proxy.getProxyUrl(video.imageUrl);
if (proxy.isCached(video.imageUrl)) {
System.out.println("result-->已缓存");
} else {
System.out.println("result-->未缓存");
mController.setImage(R.mipmap.image6);
}
mController.setLenght(240000);
mController.setOnCompletLinstener(this);
video_player.setPlayerType(NiceVideoPlayer.TYPE_IJK);
video_player.setUp(proxyUrl, null);
}
public void setData(){
video_player.restart();
video_player.start();
}
@Override
public void onComplet() {
mTask.start();
NiceVideoPlayerManager.instance().releaseNiceVideoPlayer();
}
}
activity_demo3.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.xiao.nicevideoplayer.NiceVideoPlayer
android:id="@+id/video_player"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
DataBean.java 这个是自己弄的javabean,拿进去就可以使用
public class DataBean {
public Integer imageRes;
public String imageUrl;
public String title;
public int viewType;
public DataBean(Integer imageRes, String title, int viewType) {
this.imageRes = imageRes;
this.title = title;
this.viewType = viewType;
}
public DataBean(String imageUrl, String title, int viewType) {
this.imageUrl = imageUrl;
this.title = title;
this.viewType = viewType;
}
/**
* 仿淘宝商品详情第一个是视频
* @return
*/
public static ArrayList<DataBean> getTestDataVideo() {
ArrayList<DataBean> list = new ArrayList<>();
list.add(new DataBean("http://vfx.mtime.cn/Video/2019/03/09/mp4/190309153658147087.mp4", "第一个放视频", 2));
list.add(new DataBean(R.mipmap.image1, "听风.赏雨", 1));
list.add(new DataBean(R.mipmap.image2, "迪丽热巴.迪力木拉提", 1));
list.add(new DataBean(R.mipmap.image3, "爱美.人间有之", 1));
list.add(new DataBean("http://tanzi27niu.cdsb.mobi/wps/wp-content/uploads/2017/05/2017-05-10_10-20-26.mp4", "小野在办公室用丝袜做茶叶蛋 边上班边看《外科风云》", 2));
list.add(new DataBean(R.mipmap.image5, "洋洋洋.气质篇", 1));
return list;
}
}
在TxVideoPlayerController.java中状态改变 NiceVideoPlayer.STATE_COMPLETED状态下,增加接口回调,监听当视频播放完成后在代码中操作视频对象销毁,且再次开启轮播
这个Viewpager2,目前触摸事件直接通过setOnTouchListener是无法完成,目前使用这个无效,需要通过实现dispatchTouchEvent才能完成,但是ViewPager2是final类所以无法继承,如果后续有好的方案,我会重新整理,如果你们有好的可以给我留言QQ:1335745248
由于公司代码被加密无法上次自己的Demo,所以将代码全部拷贝出来分享,以上代码自己测试了好久了,暂时处于初步阶段,后续还会继续优化,如果你们有更好的方案,我们可以一起学习进步哦
该博客介绍如何在Android应用中使用ViewPager2实现视频和图片的混合播放,包括需求描述、步骤详解以及关键代码展示。实现了视频播放完成后自动继续轮播,支持离线缓存,以及处理触摸事件的问题。

1776

被折叠的 条评论
为什么被折叠?



