Android仿抖音上下滑動切換視頻

Android仿抖音上下滑動切換視頻

?自從各大直播平臺可以滑動切換直播間后,公司就出了一大波需求橙弱,還要配合各種收費(fèi)具伍,各種VIP,很是頭疼(haha 主要是我這個人很懶纵散,不想加班)梳码,后來研究了下 ,也查閱了一些別人寫的demo和一些想法伍掀,也對此有了一些理解掰茶。

  • 1 最開始是打算用RecyclerView來實(shí)現(xiàn)的,因為他的復(fù)用性很強(qiáng)蜜笤,用起來也很方便濒蒋,和SnapHelper相結(jié)合便可以實(shí)現(xiàn)滑動分頁的功能。
    什么是 SnapHelper把兔?
    SnapHelper是一個抽象類沪伙,官方提供了一個LinearSnapHelper的子類,可以讓RecyclerView滾動停止時相應(yīng)的Item停留中間位置县好。在25.1.0版本中围橡,官方又提供了一個PagerSnapHelper的子類,可以使RecyclerView像ViewPager一樣的效果缕贡,一次只能滑一頁翁授,而且居中顯示拣播。詳細(xì)源碼解讀可以看這里讓你明明白白的使用RecyclerView——SnapHelper詳解,這里我們用到的就是PagerSnapHelper收擦。
    如何使用
    使用非常簡單贮配,只需要創(chuàng)建對象之后調(diào)用attachToRecyclerView()附著到對應(yīng)的RecyclerView對象上就可以了。
        snapHelper = new PagerSnapHelper();
        snapHelper.attachToRecyclerView(rvPage2);

?設(shè)置Adapter

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

?這樣我們就只需要監(jiān)聽RecyclerView的滾動炬守,然后就可以實(shí)現(xiàn)我們的邏輯了

  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://停止?jié)L動
                        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有個問題牧嫉,雖然可以達(dá)到切換到效果,但是如果我是上下切換减途,當(dāng)我左右快速滑動的時候酣藻,也會造成上下切換,當(dāng)然了鳍置,這個可以去監(jiān)聽他的觸摸事件辽剧,只是每一個item里面還有很多事件要處理,沖突性和復(fù)雜性會增加很多税产,就將其設(shè)置為備選方案了怕轿。所以后來接觸到上下切換的VerticalViewPager,就有了其他的方案辟拷。
    • A 和V4包的ViewPager使用一樣撞羽,適配FragmentPagerAdapter,加載多個Fragment衫冻,這樣的方式其實(shí)很簡單诀紊,很粗暴,不過性能也是很差的隅俘,不建議使用
    • B 適配PagerAdapter邻奠,監(jiān)聽setPageTransformer,加載新的數(shù)據(jù)为居,通過消息傳遞到Fragment碌宴,刷新數(shù)據(jù)
  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, "當(dāng)前加載的位置:" + pos + "--->" + mCurrentItem);
        HnLiveListModel.LiveListBean bean = list.get(pos);

        //聊天室的fragment只加載一次贰镣,以后復(fù)用
        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為數(shù)據(jù)源八孝,適配到adapter中(不過直播中業(yè)務(wù)復(fù)雜,不推薦在直播中使用鸠项,小視頻可以使用(直接一次性將數(shù)據(jù)傳遞過來))干跛,這個方式主要是為了復(fù)用播放器,這樣就不要添加多個播放器了
   for (HnChatVideoSwitchEntity item : mList) {
            if (mActivity == null) return;
            View view = LayoutInflater.from(mActivity).inflate(R.layout.adapter_invite_chat, null);
            //TODO  初始化控件
          
            //TODO  設(shè)置點(diǎn)擊事件
       
            //TODO  設(shè)置數(shù)據(jù)
           
            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));
    }

}

然后當(dāng)滑動ViewPager時祟绊,重置數(shù)據(jù)就可以了

  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);
                }
            }
        });

然后就是更新數(shù)據(jù)了

 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 設(shè)置控件數(shù)據(jù)和狀態(tài)

         //添加播放器
        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;
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末楼入,一起剝皮案震驚了整個濱河市哥捕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘉熊,老刑警劉巖遥赚,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異阐肤,居然都是意外死亡凫佛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門孕惜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愧薛,“玉大人,你說我怎么就攤上這事衫画『谅” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵削罩,是天一觀的道長瞄勾。 經(jīng)常有香客問我,道長弥激,這世上最難降的妖魔是什么进陡? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮微服,結(jié)果婚禮上四濒,老公的妹妹穿的比我還像新娘。我一直安慰自己职辨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布戈二。 她就那樣靜靜地躺著舒裤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪觉吭。 梳的紋絲不亂的頭發(fā)上腾供,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音鲜滩,去河邊找鬼伴鳖。 笑死,一個胖子當(dāng)著我的面吹牛徙硅,可吹牛的內(nèi)容都是我干的榜聂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼嗓蘑,長吁一口氣:“原來是場噩夢啊……” “哼须肆!你這毒婦竟也來了匿乃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤豌汇,失蹤者是張志新(化名)和其女友劉穎幢炸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拒贱,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宛徊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逻澳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闸天。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赡盘,靈堂內(nèi)的尸體忽然破棺而出号枕,到底是詐尸還是另有隱情,我是刑警寧澤陨享,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布葱淳,位于F島的核電站,受9級特大地震影響抛姑,放射性物質(zhì)發(fā)生泄漏赞厕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一定硝、第九天 我趴在偏房一處隱蔽的房頂上張望皿桑。 院中可真熱鬧,春花似錦蔬啡、人聲如沸诲侮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沟绪。三九已至,卻和暖如春空猜,著一層夾襖步出監(jiān)牢的瞬間绽慈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工辈毯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坝疼,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓谆沃,卻偏偏與公主長得像钝凶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子唁影,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345