拦截触摸事件并根据运动事件状态重定向触摸事件

时间:2017-11-01 10:30:08

标签: android kotlin android-custom-view ontouchevent

我在Android中创建了一个继承自RelativeLayout的自定义视图。在这个视图中是一个OverScroller,用于在触摸事件发生时处理视图的滚动:

class MyCustomView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : RelativeLayout(context, attrs, defStyleAttr) {
    constructor(context: Context) : this(context, null, 0)
    constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)
    private val scroller = OverScroller(context, FastOutLinearInInterpolator())
    private var currentY = 0
    private val gestureDetector = GestureDetectorCompat(context, object : GestureDetector.SimpleOnGestureListener() {
        override fun onDown(event: MotionEvent?): Boolean {
            // Stop the current scroll animation
            scroller.forceFinished(true)
            // Invalidate the view
            ViewCompat.postInvalidateOnAnimation(this@MyCustomView)
            return true
        }

        override fun onScroll(event1: MotionEvent?, event2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
            scroller.forceFinished(true)
            currentY -= distanceY.toInt()
            ViewCompat.postInvalidateOnAnimation(this@MyCustomView)
            return true
        }

        override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
            // Stop any scrolling
            scroller.forceFinished(true)
            scroller.fling(0, currentY, 0, velocityY.toInt(), 0, 0,
                    -5000 + height, 0)
            // Invalidate the view
            ViewCompat.postInvalidateOnAnimation(this@MyCustomView)
            return true
        }
    })

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event == null) return false
        // Return the value from the gesture detector
        return gestureDetector.onTouchEvent(event)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        // Draw stuff to canvas, using currentY as origin
    }

    override fun computeScroll() {
        // Call to super class method
        super.computeScroll()
        if (scroller.computeScrollOffset()) {
            currentY = scroller.currY
        }
        // Invalidate the view
        ViewCompat.postInvalidateOnAnimation(this@MyCustomView)
    }
}

这很好用。接下来,我添加了一个RelativeLayout视图组来保存一大堆膨胀的细胞。这些单元格是可点击的。现在,当我尝试通过第一次触摸其中一个充气单元格来启动滚动时,单元格会吞下click事件(带有滚动条的父视图永远不会被调用onTouchEvent因此不会滚动。

需要注意的重要事项:包含单元格的RelativeLayout视图组是child的{​​{1}}视图。

我已尝试在MyCustomView中覆盖onInterceptTouchEvent,以便在将触摸事件发送到任一视图之前拦截触摸事件:

MyCustomView

然后我确定触摸事件的操作代码是否为override fun onInterceptTouchEvent(event: MotionEvent?): Boolean { if (event == null) return false if (event.action == MotionEvent.ACTION_UP) { if (event.historySize > 0) { val startY = event.getHistoricalY(0) val endY = event.getHistoricalY(event.historySize - 1) val distance = Math.abs(endY - startY).toInt() if (distance == 0) { // Consider this a click (so don't swallow it return false } } } // Ok this isn't a click, so call this views onTouchEvent return this.onTouchEvent(event) } ,如果是,我计算ACTION_UPACTION_DOWN之间的总距离,如果它是'在一个足够小的范围内,我将其视为点击并调用ACTION_UP(如果事件在一个单元格上,它将点击一个膨胀的单元格,否则它将最终调用我将处理的super.onInterceptTouchEvent(event)滚动。如果事件的操作代码不是onTouchEvent或移动的距离不够小,它将返回ACTION_UP

我遇到的问题是我的解决方案无法正常工作,在充气单元格顶部开始滚动时无法启动滚动。

有谁知道我错过了什么?

0 个答案:

没有答案