使用RecyclerView实现抖音纵向滚动ViewPager效果

使用RecyclerView实现抖音纵向滚动ViewPager效果


重写LinearLayoutManager,在onAttachedToWindow方法中使用 PagerSnapHelper设置RecyclerView条目加载方式为每次滚动加载一页

class MyLinearLayoutManager : LinearLayoutManager {

    private lateinit var mPagerSnapHelper: PagerSnapHelper
    private var mOnViewPagerListener: OnViewPagerListener? = null
    private lateinit var mRecyclerView: RecyclerView
    private var mDrift: Int = 0//位移,用来判断移动方向

    constructor(context: Context) : this(context, OrientationHelper.VERTICAL)
    constructor(context: Context, orientation: Int) : this(context, orientation, false)
    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout) {
        mPagerSnapHelper = PagerSnapHelper()
    }

    override fun onAttachedToWindow(view: RecyclerView) {
        super.onAttachedToWindow(view)
        mPagerSnapHelper.attachToRecyclerView(view)//设置RecyclerView每次滚动一页
        mRecyclerView = view
        mRecyclerView.addOnChildAttachStateChangeListener(mChildAttachStateChangeListener)
    }


    /**
     * 滑动状态的改变
     * 缓慢拖拽-> SCROLL_STATE_DRAGGING
     * 快速滚动-> SCROLL_STATE_SETTLING
     * 空闲状态-> SCROLL_STATE_IDLE
     * @param state
     */
    override fun onScrollStateChanged(state: Int) {
        if (state == RecyclerView.SCROLL_STATE_IDLE){
            val viewIdle = mPagerSnapHelper.findSnapView(this)
            val positionIdle = getPosition(viewIdle!!)
            if (mOnViewPagerListener != null && childCount == 1) {
                mOnViewPagerListener!!.onPageSelected(positionIdle, positionIdle == itemCount - 1)
            }
        }
    }

    /**
     * 布局完成后调用
     * @param state
     */
    override fun onLayoutCompleted(state: RecyclerView.State?) {
        super.onLayoutCompleted(state)
        if (mOnViewPagerListener != null) mOnViewPagerListener!!.onLayoutComplete()
    }

    /**
     * 监听竖直方向的相对偏移量
     */
    override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
        this.mDrift = dy
        return super.scrollVerticallyBy(dy, recycler, state)
    }


    /**
     * 监听水平方向的相对偏移量
     */
    override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
        this.mDrift = dx
        return super.scrollHorizontallyBy(dx, recycler, state)
    }

    /**
     * 设置监听
     * @param listener
     */
    fun setOnViewPagerListener(listener: OnViewPagerListener) {
        this.mOnViewPagerListener = listener
    }

    private val mChildAttachStateChangeListener = object : RecyclerView.OnChildAttachStateChangeListener {
        override fun onChildViewAttachedToWindow(view: View) {
        }

        override fun onChildViewDetachedFromWindow(view: View) {
            if (mDrift >= 0) {
                if (mOnViewPagerListener != null) mOnViewPagerListener!!.onPageRelease(true, getPosition(view))
            } else {
                if (mOnViewPagerListener != null) mOnViewPagerListener!!.onPageRelease(false, getPosition(view))
            }

        }
    }

    interface OnViewPagerListener{
        /*释放的监听*/
        fun onPageRelease(isNext: Boolean, position: Int)

        /*选中的监听以及判断是否滑动到底部*/
        fun onPageSelected(position: Int, isBottom: Boolean)

        /*布局完成的监听*/
        fun onLayoutComplete()
    }
}

重写RecyclerView条目内容主布局满屏填充

class MyImageView : ImageView {
    constructor(context: Context) : this(context, null!!)
    constructor(context: Context, attr: AttributeSet) : this(context, attr, 0)
    constructor(context: Context, attr: AttributeSet, defStyleAttr: Int) : super(context, attr, defStyleAttr)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = View.getDefaultSize(0, widthMeasureSpec)
        val height = View.getDefaultSize(0, heightMeasureSpec)
        setMeasuredDimension(width, height)
    }

}

注:现在谷歌官方 新控件androidx.viewpager2.widget.ViewPager2可实现类似效果
代码参考:https://github.com/DingMouRen/LayoutManagerGroup

你可能感兴趣的:(自定义控件,仿抖音竖屏ViewPager,recycleView)