RecyclerView Realizes Vibrato Longitudinal Rolling ViewPager Effect
- 2021-09-20 21:23:13
- OfStack
Use RecyclerView to realize the effect of Douyin longitudinal scrolling ViewPager for your reference. The specific contents are as follows
Override LinearLayoutManager and use PagerSnapHelper in the onAttachedToWindow method to set the RecyclerView entry load mode to 1 page per scroll
class MyLinearLayoutManager : LinearLayoutManager {
private lateinit var mPagerSnapHelper: PagerSnapHelper
private var mOnViewPagerListener: OnViewPagerListener? = null
private lateinit var mRecyclerView: RecyclerView
private var mDrift: Int = 0// Displacement, which is used to judge the moving direction
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)// Settings RecyclerView Every scroll 1 Page
mRecyclerView = view
mRecyclerView.addOnChildAttachStateChangeListener(mChildAttachStateChangeListener)
}
/**
* Change of sliding state
* Slow drag -> SCROLL_STATE_DRAGGING
* Quick scroll -> SCROLL_STATE_SETTLING
* Idle state -> 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)
}
}
}
/**
* Called after the layout is complete
* @param state
*/
override fun onLayoutCompleted(state: RecyclerView.State?) {
super.onLayoutCompleted(state)
if (mOnViewPagerListener != null) mOnViewPagerListener!!.onLayoutComplete()
}
/**
* Listen for relative offsets in the vertical direction
*/
override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
this.mDrift = dy
return super.scrollVerticallyBy(dy, recycler, state)
}
/**
* Listen for relative offset in horizontal direction
*/
override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
this.mDrift = dx
return super.scrollHorizontallyBy(dx, recycler, state)
}
/**
* Set up listening
* @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{
/* Released monitor */
fun onPageRelease(isNext: Boolean, position: Int)
/* Selected monitor and determine whether to slide to the bottom */
fun onPageSelected(position: Int, isBottom: Boolean)
/* Layout completed monitoring */
fun onLayoutComplete()
}
}
Rewrite RecyclerView entry content main layout full screen fill
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)
}
}
Code reference: LayoutManagerGroup