Android仿抖音上下滑动切换视频

Android仿抖音上下滑动切换视频

 自从各大直播平台可以滑动切换直播间后,公司就出了一大波需求,还要配合各种收费,各种VIP,很是头疼(haha 主要是我这个人很懒,不想加班),后来研究了下 ,也查阅了一些别人写的demo和一些想法,也对此有了一些理解。

  • 1 最开始是打算用RecyclerView来实现的,因为他的复用性很强,用起来也很方便,和SnapHelper相结合便可以实现滑动分页的功能。
    什么是 SnapHelper
    SnapHelper是一个抽象类,官方提供了一个LinearSnapHelper的子类,可以让RecyclerView滚动停止时相应的Item停留中间位置。在25.1.0版本中,官方又提供了一个PagerSnapHelper的子类,可以使RecyclerView像ViewPager一样的效果,一次只能滑一页,而且居中显示。详细源码解读可以看这里让你明明白白的使用RecyclerView——SnapHelper详解,这里我们用到的就是PagerSnapHelper。
    如何使用
    使用非常简单,只需要创建对象之后调用attachToRecyclerView()附着到对应的RecyclerView对象上就可以了。
        snapHelper = new PagerSnapHelper();
        snapHelper.attachToRecyclerView(rvPage2);

 设置Adapter

        videoAdapter = new ListVideoAdapter(urlList);
        layoutManager = new LinearLayoutManager(Page2Activity.this, LinearLayoutManager.VERTICAL, false);
        rvPage2.setLayoutManager(layoutManager);
        rvPage2.setAdapter(videoAdapter);

 这样我们就只需要监听RecyclerView的滚动,然后就可以实现我们的逻辑了

  rvPage2.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {


            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                switch (newState) {
                    case RecyclerView.SCROLL_STATE_IDLE://停止滚动
                        View view = snapHelper.findSnapView(layoutManager);
                       //TODO 销毁所有视频
                        RecyclerView.ViewHolder viewHolder = recyclerView.getChildViewHolder(view);
                        if (viewHolder != null && viewHolder instanceof VideoViewHolder) {
                              //TODO  启动想要播放的视频
                        }
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING://拖动
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING://惯性滑动
                        break;
                }

            }
        });
  • 2 不过RecyclerView有个问题,虽然可以达到切换到效果,但是如果我是上下切换,当我左右快速滑动的时候,也会造成上下切换,当然了,这个可以去监听他的触摸事件,只是每一个item里面还有很多事件要处理,冲突性和复杂性会增加很多,就将其设置为备选方案了。所以后来接触到上下切换的VerticalViewPager,就有了其他的方案。
    • A 和V4包的ViewPager使用一样,适配FragmentPagerAdapter,加载多个Fragment,这样的方式其实很简单,很粗暴,不过性能也是很差的,不建议使用
    • B 适配PagerAdapter,监听setPageTransformer,加载新的数据,通过消息传递到Fragment,刷新数据
  class PagerAdapter extends android.support.v4.view.PagerAdapter {


        private List list;

        public PagerAdapter(List list) {
            this.list = list;
        }

        @Override
        public int getCount() {
            if (list.size() > 1) {
                return Integer.MAX_VALUE;
            } else {
                return 1;
            }
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = LayoutInflater.from(container.getContext()).inflate(R.layout.live_activity_audience_mask_layout, null);
            int pos = position % list.size();
            HnLiveListModel.LiveListBean data = list.get(pos);
            //遮罩层
            FrescoImageView mFrescoImageView = (FrescoImageView) view.findViewById(R.id.fiv_mask);
            mFrescoImageView.setVisibility(View.VISIBLE);
            if (data != null) {
                String avator = data.getAvator();
                mFrescoImageView.setController(FrescoConfig.getController(avator));
            }
            view.setId(position);
            container.addView(view);
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(container.findViewById(position));
        }
    }
  mVerticalViewPager.setPageTransformer(false, new ViewPager.PageTransformer() {
            private float yPosition;

            public float getPosition() {
                return yPosition;
            }

            @Override
            public void transformPage(View page, float position) {
                page.setTranslationX(page.getWidth() * -position);
                yPosition = position * page.getHeight();
                page.setTranslationY(yPosition);


                ViewGroup viewGroup = (ViewGroup) page;
                HnLogUtils.i(TAG, "page.id == " + page.getId() + ", position == " + position);

                if ((position < 0 && viewGroup.getId() != mCurrentItem)) {
                    View roomContainer = viewGroup.findViewById(R.id.room_container);
                    if (roomContainer != null && roomContainer.getParent() != null && roomContainer.getParent() instanceof ViewGroup) {
                        ((ViewGroup) (roomContainer.getParent())).removeView(roomContainer);
                    }
                }
                // 满足此种条件,表明需要加载直播视频,以及聊天室了
                if (viewGroup.getId() == mCurrentItem && position == 0 && mCurrentItem != mRoomUid) {
                    if (mRoomContainer.getParent() != null && mRoomContainer.getParent() instanceof ViewGroup) {
                        ((ViewGroup) (mRoomContainer.getParent())).removeView(mRoomContainer);
                    }
                    EventBus.getDefault().post(new HnLiveEvent(0, HnLiveConstants.EventBus.Close_Dialog, 0));
                    EventBus.getDefault().post(new HnLiveEvent(0, HnLiveConstants.EventBus.Hide_Mask, 0));
                    loadVideoAndChatRoom(viewGroup, mCurrentItem);
                }
            }
        });

 /**
     * 加载房间信息
     *
     * @param viewGroup
     * @param mCurrentItem
     */
    private void loadVideoAndChatRoom(ViewGroup viewGroup, int mCurrentItem) {
        pos = mCurrentItem % list.size();
        HnLogUtils.i(TAG, "当前加载的位置:" + pos + "--->" + mCurrentItem);
        HnLiveListModel.LiveListBean bean = list.get(pos);

        //聊天室的fragment只加载一次,以后复用
        if (!mInit) {
            mRoomFragment = HnAudienceRoomFragment.newInstance(bean);
            mFragmentManager.beginTransaction().replace(R.id.fragment_container, mRoomFragment).commitAllowingStateLoss();
            mInit = true;
        } else {
            if (mRoomFragment == null) {
                mRoomFragment = HnAudienceRoomFragment.newInstance(bean);
                mFragmentManager.beginTransaction().replace(R.id.fragment_container, mRoomFragment).commitAllowingStateLoss();
                mInit = true;
            }
            EventBus.getDefault().post(new HnLiveEvent(0, HnLiveConstants.EventBus.Update_Room_Info, bean));
        }
        viewGroup.addView(mRoomContainer);
        this.mRoomUid = mCurrentItem;
    }

  • C 适配PagerAdapter,初始化每个Item的View ,以View为数据源,适配到adapter中(不过直播中业务复杂,不推荐在直播中使用,小视频可以使用(直接一次性将数据传递过来)),这个方式主要是为了复用播放器,这样就不要添加多个播放器了
   for (HnChatVideoSwitchEntity item : mList) {
            if (mActivity == null) return;
            View view = LayoutInflater.from(mActivity).inflate(R.layout.adapter_invite_chat, null);
            //TODO  初始化控件
          
            //TODO  设置点击事件
       
            //TODO  设置数据
           
            mViews.add(view);
        }

adapter里面很简单

public class HnInviteChatAdapter extends PagerAdapter {

    private static final String TAG = "DouYinAdapter";

    private List mViews;

    public HnInviteChatAdapter(List views) {
        this.mViews = views;
    }


    public void setmViews(List mViews) {
        this.mViews = mViews;
    }

    @Override
    public int getCount() {
        return mViews.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        Log.d(TAG, "instantiateItem: called");
        container.addView(mViews.get(position));
        return mViews.get(position);
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        Log.d(TAG, "destroyItem: ");
        container.removeView(mViews.get(position));
    }

}

然后当滑动ViewPager时,重置数据就可以了

  mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                mCurrentItem = position;
                //TODO视频暂停播放
                if (mIjkVideoView != null) {
                    mIjkVideoView.pause();
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                if (mPlayingPosition == mCurrentItem) return;
                if (state == VerticalViewPager.SCROLL_STATE_IDLE) {
                    //TODO视频暂停播放
                    stopPlay();
                    //TODO 重置一些控件显示与否
                    releaseView();
                    ViewParent parent = mIjkVideoView.getParent();
                    //TODO移除上个页面的视频控件
                    if (parent != null && parent instanceof FrameLayout) {
                        ((FrameLayout) parent).removeView(mIjkVideoView);
                    }
                    getAnchorData(mCurrentItem);
                }
            }
        });

然后就是更新数据了

 private void getAnchorData(int position) {
        mUid = mList.get(position).getUser_id();
        mDbean = mList.get(position);
        mPlayUrl = mDbean.getUser_video();
        
        mCurrentItem = position;
    
        View view = mViews.get(mCurrentItem);
        RelativeLayout mContainer = view.findViewById(R.id.mContainer);
        initItemView(view);
        //TODO 设置控件数据和状态

         //添加播放器
        ViewGroup parent = (ViewGroup) mIjkVideoView.getParent();
        if (parent != null) {
            parent.removeAllViews();
        }
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
        params.addRule(RelativeLayout.CENTER_IN_PARENT);
        mIjkVideoView.setLayoutParams(params);
        mContainer.addView(mIjkVideoView, 0, params);


        startPlay();
        mPlayingPosition = mCurrentItem;
    }

你可能感兴趣的:(Android仿抖音上下滑动切换视频)