Android ViewPager2实现视频与图片混合播放

该博客介绍如何在Android应用中使用ViewPager2实现视频和图片的混合播放,包括需求描述、步骤详解以及关键代码展示。实现了视频播放完成后自动继续轮播,支持离线缓存,以及处理触摸事件的问题。

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,所以将代码全部拷贝出来分享,以上代码自己测试了好久了,暂时处于初步阶段,后续还会继续优化,如果你们有更好的方案,我们可以一起学习进步哦

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值