RecyclerView+PageSnapHelper实现ViewPager效果+自动翻页

预期效果是大多app都会用到的首页顶部图片banner,3s自动轮播,也可手动切换

用法很简单,做attach就好(以下为kotlin代码)

recyclerView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
val snapHelper = PagerSnapHelper()
snapHelper.attachToRecyclerView(recyclerView)

自动翻页是定义的handler每3s执行一次bannerPos++然后recyclerView滚动,但是注意滚动的方法要使用

recyclerView.smoothScrollToPosition(bannerPos)

使用的话scrollToPosition()就不会有左右平滑的效果

如果需要同步更新Indicator,在recyclerView的滑动监听里

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                    override fun onScrollStateChanged(recycler: RecyclerView, newState: Int) {
                        super.onScrollStateChanged(recycler, newState)
                        when (newState) {
                            RecyclerView.SCROLL_STATE_IDLE -> {
                                val viewIdle = snapHelper.findSnapView(recyclerView.layoutManager)
                                if (viewIdle != null) {
                                    val pos = recyclerView.layoutManager?.getPosition(viewIdle) ?: 0
                                    updateIndicators(pos)
                                }
                            }
                        }
                    }
                })
  /**
     * 更新到当前指示器
     */
    private fun updateIndicators(position: Int) {
        for (i in 0 until indicatorContainer.childCount) {
            val childView = indicatorContainer.getChildAt(i)
            childView.background = if (position == i)
               resources.getDrawable(R.drawable.shape_indicator_orange)
            else
               resources.getDrawable(R.drawable.shape_indicator_gray)
        }
    }

补充一下indicator的初始化方法

private fun setIndicators(bannerList: List<String>?) {
        //只有一页的时候不显示指示器
        if (bannerList?.size ?: 0 <= 1) {
            return
        }
        indicatorContainer.removeAllViews()
        for (i in bannerList!!.indices) {
            val indicatorView = View(context)
            indicatorView.background = resources.getDrawable(R.drawable.shape_indicator_gray)
            val layoutParams: LinearLayout.LayoutParams = LinearLayout.LayoutParams(
                ConvertUtils.dp2px(6f), ConvertUtils.dp2px(6f)
            )
            if (i != 0) layoutParams.leftMargin = ConvertUtils.dp2px(8f)
            indicatorView.layoutParams = layoutParams
            indicatorContainer.addView(indicatorView)
        }
        updateIndicators(indicatorContainer, 0)
    }

 

我这里把整个页面都用一个recyclerView展示的,所以顶部banner也作为一个item嵌在数据里(感觉还是addHeader方法合理哈),嵌套在里面要更新呢就更新adapter,当时发现自动翻页时滑动起来有重复页面闪过的情况,这是因为adapter做notify的时候每次都重置到了第一页再调用前面说的smooth方法滑动,所以中间页面会展示出快速划过。

所以我在调用smooth滑动之前先把banner用scrollToPosition()方法无痕迹滑动到前一张,这样就看不出闪页了

if (bannerPos > 0){
    recyclerView.scrollToPosition(bannerPos-1)
}

 

posted @ 2021-08-17 17:12  Sharley  阅读(1959)  评论(0编辑  收藏  举报