TouchDelegate的困惑

105 阅读2分钟

第一次看到这个类名,我以为能顺利的把所有的事件在被代理的那个view里面拿到。

实践了一下,确实能到事件,但是莫名其妙的 x y变成固定值了,我特么fuck了呀。

敢情这个TouchDelegate只是把事件转移到了这个view上面,但是X,Y都改的面目全非了。

public boolean onTouchEvent(MotionEvent event) {
        int x = (int)event.getX();
        int y = (int)event.getY();
        //是否发生event事件给需要代理的view
        boolean sendToDelegate = false;
        //是否点击在需代理的view上,这里不好翻译,大致意思看后面
        boolean hit = true;
        //是否已处理
        boolean handled = false;

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Rect bounds = mBounds;
//down事件包含在rect区域里,要发event事件给需代理的view
            if (bounds.contains(x, y)) {
                mDelegateTargeted = true;
                sendToDelegate = true;
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_MOVE:
            sendToDelegate = mDelegateTargeted;
            if (sendToDelegate) {
                Rect slopBounds = mSlopBounds;
                //用ScaleTouchSlop扩大的区域是否包含了event的x y坐标,hit默认为true,默认包含
                if (!slopBounds.contains(x, y)) {
                    hit = false;
                }
            }
            break;
        case MotionEvent.ACTION_CANCEL:
            sendToDelegate = mDelegateTargeted;
            mDelegateTargeted = false;
            break;
        }
        if (sendToDelegate) {
            final View delegateView = mDelegateView;

            if (hit) {
                // Offset event coordinates to be inside the target view
                //这里重设了event的坐标,改成固定左边坐标了
                event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2);
            } else {
                // Offset event coordinates to be outside the target view (in case it does
                // something like tracking pressed state)
                int slop = mSlop;
                //上面英文解释也很清楚,是为了追踪preesed状态的,就是当move事件一直移动还没up前移出了设定的rect点击区域的时候需要重写设置event的坐标
                event.setLocation(-(slop * 2), -(slop * 2));
            }
            handled = delegateView.dispatchTouchEvent(event);
        }
        return handled;
    }

看最后的 event.setLocation瞬间一口老血吐出来了。照这样,只能作为扩大view的点击区域用了。并不能作为扩大view的滑动响应区域。


参考SearchView里面自定了TouchDelegate修改了一番

class UpdatableTouchDelegate(
    targetBounds: Rect,
    actualBounds: Rect,
    delegateView: View
) : TouchDelegate(targetBounds, delegateView) {
    companion object {
        private const val TAG = "UpdatableTouchDelegate"
    }

    /**
     * View that should receive forwarded touch events
     */
    private val mDelegateView: View

    /**
     * Bounds in local coordinates of the containing view that should be mapped to the delegate
     * view. This rect is used for initial hit testing.
     */
    private val mTargetBounds: Rect

    /**
     * Bounds in local coordinates of the containing view that are actual bounds of the delegate
     * view. This rect is used for event coordinate mapping.
     */
    private val mActualBounds: Rect

    /**
     * True if the delegate had been targeted on a down event (intersected mTargetBounds).
     */
    private var mDelegateTargeted = false

    init {
        mTargetBounds = Rect()
        mActualBounds = Rect()
        setBounds(targetBounds, actualBounds)
        mDelegateView = delegateView
    }

    fun setBounds(desiredBounds: Rect, actualBounds: Rect) {
        mTargetBounds.set(desiredBounds)
        mActualBounds.set(actualBounds)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val x = event.x.roundToInt()
        val y = event.y.roundToInt()
        var sendToDelegate = false
        var handled = false
        when (event.action) {
            MotionEvent.ACTION_DOWN -> if (mTargetBounds.contains(x, y)) {
                mDelegateTargeted = true
                sendToDelegate = true
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_MOVE -> {
                sendToDelegate = mDelegateTargeted
            }
            MotionEvent.ACTION_CANCEL -> {
                sendToDelegate = mDelegateTargeted
                mDelegateTargeted = false
            }
        }
        if (sendToDelegate) {
            // Offset event coordinates to the target view coordinates.
            event.offsetLocation(-mActualBounds.left.toFloat(), -mActualBounds.top.toFloat())
            handled = mDelegateView.dispatchTouchEvent(event)
        }
        return handled
    }
}

ennnnnnn~ 愉快的拿到了会变动的x和y了