ViewDragHelper与listview的事件分发滑动冲突

2024-07-09  本文已影响0人  爱学习的猫叔

效果图

Screen_recording_20240710_075918.gif

代码实现

class CustomDragView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0,
) : FrameLayout(context, attrs, defStyleAttr) {

    lateinit var mFrontChild: View
    lateinit var mBackChild: View

    private var mFrontChildHeight = 0

    private var mTop = 0

    private var mDownY = 0f

    private var mIsMenuOpen = false

    private var mVhCb = object : ViewDragHelper.Callback() {

        override fun tryCaptureView(child: View, pointerId: Int): Boolean {
            return child == mBackChild
        }

        override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {
            Log.i(TAG, "top:$top,dy:$dy")
            mTop = top
            return if (top > mFrontChildHeight) mFrontChildHeight else if (top < 0) 0 else top
        }

        override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) {
            super.onViewReleased(releasedChild, xvel, yvel)
            Log.i(TAG, "yvel:$yvel")
            if (releasedChild == mBackChild) {
                mIsMenuOpen = mTop > mFrontChildHeight / 3
                mVH.settleCapturedViewAt(0, if (mIsMenuOpen) mFrontChildHeight else 0)
                invalidate()
            }
        }
    }

    override fun computeScroll() {
        if (mVH.continueSettling(true)) {
            invalidate()
        }
    }

    private var mVH: ViewDragHelper = ViewDragHelper.create(this, mVhCb)

    override fun onFinishInflate() {
        super.onFinishInflate()
        if (childCount > 2) {
            throw RuntimeException("only allow two direct children")
        }

        mFrontChild = getChildAt(0)
        mBackChild = getChildAt(1)
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        if (changed) {
            mFrontChildHeight = mFrontChild.measuredHeight
            Log.i(TAG, "frontChildHeight:$mFrontChildHeight")
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        mVH.processTouchEvent(event)
        return true
    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        //一旦菜单打开全部拦截不给listview处理
        if (mIsMenuOpen) {
            return true
        }
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                //down事件传递给ViewDragHelper
                mVH.processTouchEvent(ev)
                mDownY = ev.y
            }

            MotionEvent.ACTION_MOVE -> {
                val diffY = ev.y - mDownY
                Log.d(TAG, "diff:$diffY")
                if (diffY > 0 && !canScrollUp()) {
                    return true
                }
            }
        }
        //事件分发给child
        return super.onInterceptTouchEvent(ev)
    }

    private fun canScrollUp(): Boolean {
        var result = false
        if (mBackChild is AbsListView) {
            val listView = (mBackChild as AbsListView)
            result = listView.childCount > 0 && listView.firstVisiblePosition > 0
        }
        val result2 = mBackChild.canScrollVertically(-1)
        Log.i(TAG, "result:$result,result2:$result2")
        return result2 || result
    }

    companion object {
        private const val TAG = "CustomDragView"
    }
}

代码地址

https://github.com/treech/MyView

上一篇 下一篇

猜你喜欢

热点阅读