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

Android仿抖音上下滑动切换视频
https://www.jianshu.com/p/af9c0e46725d

 自从各大直播平台可以滑动切换直播间后,公司就出了一大波需求,还要配合各种收费,各种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<HnLiveListModel.LiveListBean> list;

        public PagerAdapter(List<HnLiveListModel.LiveListBean> 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<View> mViews;

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


    public void setmViews(List<View> 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;
    }



作者:TXswim
链接:https://www.jianshu.com/p/af9c0e46725d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在模仿抖音上下滑动视频时,可以使用jQuery(简称jq)来实现。 首先,需要在HTML中创建一个父容器,用于展示视频列表。可以使用`<div>`标签,并为其指定一个唯一的ID,比如`#video-container`。 接下来,在JavaScript代码中,可以通过jq选择器选中该父容器元素,并使用`on`方法来监听滑动事件,即`scroll`事件。 具体而言,可以使用以下代码实现: ```javascript $(document).ready(function(){ $('#video-container').on('scroll', function(){ // 判断滚动方向,如果是向下滚动 if($(this).scrollTop() + $(this).innerHeight() >= this.scrollHeight) { // 向下加载新的视频数据 // 代码逻辑... } // 判断滚动方向,如果是向上滚动 if($(this).scrollTop() <= 0) { // 向上加载新的视频数据 // 代码逻辑... } }); }); ``` 在上述代码中,当用户通过滑动手势向下滚动到页面底部时,会触发`scroll`事件,然后通过判断滚动距离和容器高度是否等于或大于父容器总高度,来判断用户是否浏览到了最底部。类似地,当用户向上滚动到页面顶部时,会触发`scroll`事件,并通过判断滚动距离是否小于等于0来判断用户是否浏览到了最顶部。 在滚动到底部或顶部时,可以编写相关的代码来加载新的视频数据,并将其插入到父容器中,从而实现模仿抖音上下滑动视频的效果。 以上就是使用jq模仿抖音上下滑动视频的基本思路,具体实现可根据需求进行进一步调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值