Android MotionEvent: 如何判断触摸事件是否发生在视图之外

13
我有一个按钮和附加在上面的OnTouchListener。如何判断用户按下按钮时发生的动作(motion)是在按钮内还是外部?event.getAction() 和 event.getActionMasked() 都只返回0、1或2,分别表示ActionDown、ActionUp和ActionMove。有一个常量MotionEvent.ACTION_OUTSIDE,值为4,但即使我将触摸拖到按钮外面,仍然无法收到它,而是从两种方法中都收到2。问题出在哪里? 更新:我找到了一个好的解决办法——在ACTION_UP之后检查视图的焦点状态。如果没有焦点,那么意味着移动事件发生在视图之外。
7个回答

15

MotionEvent.ACTION_OUTSIDE不适用于View。

一个解决方案是获取X和Y触摸位置,并验证它是否在View的边界内。可以这样做:

@Override
public boolean onTouchEvent(MotionEvent e) {
    if (isInside(myView, e))
        Log.i(TAG, "TOUCH INSIDE");
    else
        Log.i(TAG, "TOUCH OUTSIDE");
    return true;
}

private boolean isInside(View v, MotionEvent e) {
    return !(e.getX() < 0 || e.getY() < 0
            || e.getX() > v.getMeasuredWidth()
            || e.getY() > v.getMeasuredHeight());
}

isInside函数的实现不正常,参数没有传递到isInside函数中,那个答案确实需要编辑。这里有一个对我有效的解决方案https://dev59.com/w5Tfa4cB1Zd3GeqPYf3c#73111775 - Slion

9
该标志仅适用于Windows,而不适用于Views。当您将手指移出视图时,将获得ACTION_MOVE事件,该事件保留在其起源视图中。如果需要澄清,请查看SeekBar的源代码:即使您将手指移出滑动条,拇指仍然会拖动!若要在Window级别执行此操作,请使用FLAG_WATCH_OUTSIDE_TOUCH,它可以正常工作。

8

MotionEvent.ACTION_CANCEL 对我的问题起作用。


4
如果OnTouchListenerButton上,你只会收到来自Button内部的动作事件。当动作事件第一次超出View的边界时,MotionEvent.ACTION_OUTSIDE将仅被调用,并且您应该将其视为ACTION_UP。请注意保留HTML标记。

1
public static boolean touchWithinBounds(MotionEvent event, View view) {
    if (event == null || view == null || view.getWidth() == 0 || view.getHeight() == 0)
        return false;

    int[] viewLocation = new int[2];
    view.getLocationOnScreen(viewLocation);
    int viewMaxX = viewLocation[0] + view.getWidth() - 1;
    int viewMaxY = viewLocation[1] + view.getHeight() - 1;
    return (event.getRawX() <= viewMaxX && event.getRawX() >= viewLocation[0]
        && event.getRawY() <= viewMaxY && event.getRawY() >= viewLocation[1]);
}

当您从不同的视图转发触摸事件时的解决方案

0

试一下这个

private View.OnTouchListener handleTouch = new View.OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {

    int x = (int) event.getX();
    int y = (int) event.getY();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.i("TAG", "touched down");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i("TAG", "moving: (" + x + ", " + y + ")");
            break;
        case MotionEvent.ACTION_UP:
            Log.i("TAG", "touched up");
            // do what you want when touch active
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.if("TAG","touched canceled")
            // outside of the view 
            //ACTION_MOVE present 
            break:

    }

    return true;
}

};


0
这是一个 Kotlin 扩展函数,您可以从触摸监听器中使用它来检查提供的事件是否在给定的视图内:
private fun MotionEvent.isInside(v: View): Boolean {
    return Rect().apply(v::getGlobalVisibleRect).contains(rawX.toInt(), rawY.toInt())
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接