SpringLayout 粘性线性布局

291 阅读2分钟

粘性线性布局

SpringNSView

/**
 * Created by zmp on 2019/11/15 10:18
 * 粘性线性布局布局
 *
 * @author zmp
 */
class SpringNSView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) :
    LinearLayout(context, attrs, defStyleAttr), NestedScrollingParent2 {
    private var mScroller: Scroller = Scroller(context)

    override fun onNestedScrollAccepted(child: View, target: View, axes: Int, type: Int) {
        Log.e("SpringNSView", "onNestedScrollAccepted")
    }

    override fun onStopNestedScroll(target: View, type: Int) {
        mScroller.startScroll(scrollX, scrollY, -scrollX, -scrollY, 500)
        invalidate()

    }

    override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean {
        return true
    }

    override fun computeScroll() {
        super.computeScroll()
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.currX, mScroller.currY)
            invalidate()
        }
    }

    override fun onNestedScroll(
        target: View,
        dxConsumed: Int,
        dyConsumed: Int,
        dxUnconsumed: Int,
        dyUnconsumed: Int,
        type: Int
    ) {
    }


    override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
        if (type == 1) {
            return
        }
        mScroller.forceFinished(true)
        if (orientation == HORIZONTAL) {
            preScrollHorizontally(target, dx, type, consumed)
        } else {
            preScrollVertically(target, dy, type, consumed)
        }
    }

    private fun preScrollHorizontally(
        target: View,
        dx: Int,
        type: Int,
        consumed: IntArray
    ) {
        val b = !target.canScrollHorizontally(-1)
        val b2 = !target.canScrollHorizontally(1)
        Log.e("SpringNSView", "onNestedPreScroll:$dx...$scrollX..$type..$b")
        if ((b && dx < 0) || scrollX < 0) {
            var i = if (dx < 0) {
                scrollX + dx / (1 * abs(scrollX / 10) + 1)
            } else {
                scrollX + dx
            }
            if (i > 0) {
                i = 0
            } else if (i < -measuredWidth / 2)
                i = -measuredWidth / 2
            consumed[0] = dx
            scrollTo(i, scrollY)
        }

        if ((b2 && dx > 0) || scrollX > 0) {
            var i = if (dx > 0) {
                scrollX + dx / (1 * abs(scrollX / 10) + 1)
            } else {
                scrollX + dx
            }
            if (i > measuredWidth / 2) {
                i = measuredWidth / 2
            } else if (i < 0)
                i = 0
            consumed[0] = dx
            scrollTo(i, scrollY)
        }
    }

    private fun preScrollVertically(
        target: View,
        dy: Int,
        type: Int,
        consumed: IntArray
    ) {
        val b = !target.canScrollVertically(-1)
        val b2 = !target.canScrollVertically(1)
        Log.e("SpringNSView", "onNestedPreScroll:$dy...$scrollY..$type..$b")
        if ((b && dy < 0) || scrollY < 0) {
            var i = if (dy < 0) {
                scrollY + dy / (1 * abs(scrollY / 10) + 1)
            } else {
                scrollY + dy
            }
            if (i > 0) {
                i = 0
            } else if (i < -measuredHeight / 2)
                i = -measuredHeight / 2
            consumed[1] = dy
            scrollTo(scrollX, i)
        }

        if ((b2 && dy > 0) || scrollY > 0) {
            var i = if (dy > 0) {
                scrollY + dy / (1 * abs(scrollY / 10) + 1)
            } else {
                scrollY + dy
            }
            if (i > measuredHeight / 2) {
                i = measuredHeight / 2
            } else if (i < 0)
                i = 0
            consumed[1] = dy
            scrollTo(scrollX, i)
        }
    }

    override fun onNestedFling(
        target: View,
        velocityX: Float,
        velocityY: Float,
        consumed: Boolean
    ): Boolean {
        return false
    }

    override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
        return false
    }
}

xml 方向左右android:orientation="horizontal" 上下 vertical

<?xml version="1.0" encoding="utf-8"?>
<com.zmp.pagedemo.view.SpringNSView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorAccent"
    android:orientation="horizontal">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</com.zmp.pagedemo.view.SpringNSView>