相似抖音直播間滑動加載頁

做者:蒼王 時間:2018.7.17git

如下是我這個系列的相關文章,有興趣能夠參考一下,能夠給個喜歡或者關注個人文章。github

[Android]如何作一個崩潰率少於千分之三噶應用app--章節列表bash

Android組件化架構熱賣中

如今不少直播軟件都具有無限循環加載的功能還有就是羣聊圖片預覽,這節就分析一下,這種功能的實現。網絡

1.ViewPager的製做無限循環架構

2.RecylerView滑動,使它能夠定在其中的完整的一格app

3.自定義View和Layout達到滑動效果。ide

先給你們看看ViewPager的作法吧。其至少須要4個View來完成對象複用組件化

ViewPager複用.png

private fun initView() {
        // 初始化複用的預覽界面,4個足夠知足滑動調度
        for (i in 0..3) {
            val previewView = MediaPreviewView(this)
            previewView.tag = i
            previewViews.add(previewView)
        }
       //自定義pagerAdapter
        mediaview_viewpager.adapter = object : PagerAdapter() {
            override fun instantiateItem(container: ViewGroup, position: Int): Any {
                Log.i(TAG, "View index = ${(position) % 4}, position = $position, current position = $currentPosition")
                val message = mediaItems[position]
                val previewView = previewViews[(position) %4]  //獲取複用的view
                // 設置媒體數據
                previewView.setMediaItem(message)
                if (previewView.parent == null) {  //添加View
                    container.addView(previewView)
                }
                return previewView
            }
            //清空View中的內容,以便複用
            override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
                val previewView = previewViews[(position) % 5]
                previewView.clear()
            }

            override fun isViewFromObject(view: View, `object`: Any): Boolean {
                return view == `object`
            }
            //獲取adapter的數據量
            override fun getCount() = mediaItems.size
            
            override fun getItemPosition(`object`: Any): Int {
                return if ((`object` as View).tag as Int == (currentPosition) % 5) {
                    POSITION_UNCHANGED
                } else {
                    POSITION_NONE
                }
            }
        }
        //添加滑動監聽
        mediaview_viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrollStateChanged(state: Int) {}

            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

            override fun onPageSelected(position: Int) {
                if (position != currentPosition) {
                    currentPosition = position
                    lastIndexId = mediaItems[position].indexId
                    if (position == 0) { //到第一個向前請求更多數據
                        getForwardMessages()
                    }
                    if (position == mediaItems.lastIndex) {  //到末尾向後請求更多數據
                        getBackwardMessages()
                    }
                }
            }
        })
    }
複製代碼

這裏數據變動的時候,ViewPager會強制要求你刷新界面。若是你滑動的時候在網絡獲取數據地址,ViewPager強制刷新,你就發現忽然黑屏了一下。。。這體驗,真的很是差的。。。flex

Viewpager是沒提供局部刷新的方法的,因此這個bug也沒法修復,除非你重寫整個Viewpager了,可是這樣也不利於後續優化維護。優化

若是滑動是循環且數量是肯定的,能夠採起這種方案,可是須要動態更新數據,就不能採起這種方案了,體驗不好。 直播滑動和在線圖片輪播是須要動態加載,因此此方案不適用。

2.使用RecylerView的卡位的方案,這裏很是簡單,只須要PagerSnapHelper直接關聯RecylerView,ReyclerView會直接完成View複用。而RecylerView擁有局部刷新的接口功能,因此不會出現閃屏的功能。

private fun initView() {
        mediaview_recycler.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
        mediaview_recycler.adapter = MediaViewAdapter()
        mediaview_recycler.isNestedScrollingEnabled = false
        //這裏簡單使用PagerSanpHepler關聯到RecylverView就能夠了
        PagerSnapHelper().apply {
            attachToRecyclerView(mediaview_recycler)
        }
    }
複製代碼

局部向前刷新

private fun getForwardMessages() {
          mediaItems.addAll(0, it)
          mediaview_recycler.adapter.notifyItemRangeInserted(0, it.size)
          mediaview_recycler.adapter.notifyItemRangeChanged(0, mediaItems.size)

    }
複製代碼

局部向後刷新

private fun getBackwardMessages() {
         if (it.isNotEmpty()) {
                 mediaItems.addAll(it)
                 mediaview_recycler.adapter.notifyItemInserted(mediaItems.size - it.size)
         }
    }
複製代碼

SnapHelper還有一個居中的效果的LinearSnapHelper

這裏若是還須要判斷視頻播放時機,須要複寫LayoutManager的方法。能夠參考下面的文章 Android中模仿抖音的滑動RecycleView的實現

有這個PageRecylerView的開源庫,可是反射了使用了RecylerView的mViewFlinger對象,若是上線google play是沒法使用的。

https://github.com/ckrgithub/PageRecyclerView

3.自定義layout 這個開源是大神五年前寫的,感受就是ViewPager的原版。數據變動也須要強刷整個頁面,因此會有閃屏的問題,須要改寫刷新頁面的方式爲局部刷新。

https://github.com/castorflex/VerticalViewPager

……2018.7.17更新…… 1.若是播放器存在進度條,那麼recylerView就須要劃分一個區域,觸摸事件向下傳遞,複寫攔截事件。

var canSmoothDownSide = false //true表示能夠滑動,false表示不能夠
    override fun onInterceptTouchEvent(e: MotionEvent?): Boolean {
        if (e?.action == MotionEvent.ACTION_MOVE && !canSmoothDownSide) {
            if (e.rawY > ScreenUtils.getScreenHeight(context) - ScreenUtils.dp2Px(context, 80f)) {
                return false
            }
        }
        return super.onInterceptTouchEvent(e)
    }
複製代碼

2.使用Exoplayer播放,ExoPlayerView,播放(true)和暫停(false)都是使用setPlayWhenReady,若是你使用了stopVideo來暫停,當recylerView滑動後再劃回來會黑屏。一個ExoPlayerView,沒法設置兩次prepare MediaSource做爲替換,否則會顯示AudioFlinger could not create Task。

3.Exoplayer,如何視頻過短(1~3秒)恢復過來會有黑屏的問題。視頻有時候也會由於recylerView切換後沒法卡在中止的那幀,沒法播放。解決的方法是使用RecylerView onChildViewAttachedToWindow的時候,從新設置進度播放進度。

天星技術團QQ:557247785。

相關文章
相關標籤/搜索