onTouch:检测 ACTION_UP 而不阻塞其他触摸事件

onTouch: detect ACTION_UP without blocking other touch events

我有一个用作按钮的自定义视图。 canvas 都是我自己画的。现在我在 ACTION_DOWN 时制作大纲,并在 ACTION_UPACTION_CANCEL 后删除它。

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.e("test", "ACTION_DOWN");
            break;
        case MotionEvent.ACTION_UP:
            Log.e("test", "ACTION_UP");
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.e("test", "ACTION_CANCEL");
            break;
    }

    return true;
}

这对我有用,除了现在它阻止了此视图后面的另一个手势,该手势正在检测 ACTION_MOVE(向左滚动)。

如果我 return 为假,那么它工作正常但现在 ACTION_UP 没有被调用。

如果手指被抬起,我想调用 ACTION_UP,否则传递事件。

您是否尝试过覆盖 dispatchTouchEvent

https://developer.android.com/reference/android/view/View.html#dispatchTouchEvent(android.view.MotionEvent)

更新:

所以触摸事件有点像野兽。 运行下面是这个...

  1. 它们首先从您 Activity 的根容器中冒出来。这是通过调用 dispatchTouchEvent 然后 onInterceptTouchEvent 假设拦截没有被子视图阻止来完成的。
  2. 如果没有view拦截事件,就会冒泡到调用onTouch的叶子节点(比如按钮)。如果节点不处理它 (returns true) 它的父节点有机会等等。

这意味着您可以使用 dispatchTouchEventonInterceptTouchEvent 来监视触摸事件而不改变行为。除非你真的要拦截我建议使用 dispatchTouchEvent 的事件,因为它保证 运行 而拦截可能会被阻止(例如:DrawerLayout 将拦截边缘附近的触摸事件,以便打开抽屉)。

所以最后的结果是:

public class MyView extends Button {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                Log.e("test", "ACTION_DOWN");
                break;
            case MotionEvent.ACTION_UP:
                Log.e("test", "ACTION_UP");
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.e("test", "ACTION_CANCEL");
                break;
        }
        return super.dispatchTouchEvent(event);
    }
}

更新:

抱歉,出于某种原因(主要是我的阅读能力差)我一直以为我们是在和家长打交道。这是我会做的...

继续执行 onTouch 和 return true 以消耗所有事件。这意味着在您的视图上开始的任何触摸事件都将被吃掉。然后我们要做的是将点转换为父坐标 space 并手动向上传递触摸事件,它在您的自定义视图中看起来像这样...

private boolean passingTouchEventToParent = true;
final private Rect hitRect = Rect();
@Override
public boolean onTouch(MotionEvent event) {
    // Handle your custom logic here

    final ViewParent viewParent = getParent();
    if (passingTouchEventToParent &&
            viewParent != null &&
            viewParent instanceof View) {
        // Gets this view's hit rectangle in the parent's space
        getHitRect(hitRect);
        event.offsetLocation((float) hitRect.left, (float) hitRect.top);
        passingTouchEventToParent = viewParent.onTouchEvent(event);
    }
    if (event.getActionMasked() == MotionEvent.ACTION_UP) {
        // Motion event finished, reset passingTouchEventToParent
        passingTouchEventToParent = true;
    }
    return true;
}