Android:检测用户是否触摸并拖出按钮区域?

ant*_*afe 49 android button gestures

在Android中,我们如何检测用户是否触摸按钮并拖出此按钮的区域?

Ent*_*eco 89

检查MotionEvent.MOVE_OUTSIDE:检查MotionEvent.MOVE:

private Rect rect;    // Variable rect to hold the bounds of the view

public boolean onTouch(View v, MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        // Construct a rect of the view's bounds
        rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());

    }
    if(event.getAction() == MotionEvent.ACTION_MOVE){
        if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
            // User moved outside bounds
        }
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

注意:如果您想要定位Android 4.0,则会打开全新的可能性:http: //developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER

  • 根据这个答案(http://stackoverflow.com/questions/6162497/when-would-action-outside-be-triggered/8059266#8059266)我相信我们只能使用ACTION_OUTSIDE来检测触摸是否在活动之外,而不是一个看法. (4认同)

Fro*_*ket 21

Entreco发布的答案在我的案例中需要稍微调整一下.我不得不替换:

if(!rect.contains((int)event.getX(), (int)event.getY()))
Run Code Online (Sandbox Code Playgroud)

对于

if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY()))
Run Code Online (Sandbox Code Playgroud)

因为event.getX()并且event.getY()仅适用于ImageView本身,而不适用于整个屏幕.


Boy*_*Boy 5

我在OnTouch中添加了一些日志记录,发现它MotionEvent.ACTION_CANCEL被点击了.这对我来说已经足够了......

  • 如果你的`View`包含在像`ScrollView`之类的父ViewGroup中,你会得到一个`MotionEvent.ACTION_CANCEL`回调,它有兴趣从它的孩子那里偷走移动触摸,但是不能保证你会得到一个`MotionEvent ``View`中的.ACTION_CANCEL`回调. (2认同)

Adi*_*ain 5

我遇到了与OP相同的问题,我想知道什么时候(1)某个特定的View物体被按下,以及(2)何时在上释放了向下的接触,View或者(3)当向下的接触超出了范围时的View。我在此线程中汇总了各种答案,以创建View.OnTouchListener(名为SimpleTouchListener)的简单扩展,这样其他人就不必摆弄MotionEvent对象了。该类的来源可以在此处或此答案的底部找到。

要使用此类,只需将其设置为方法的单个参数即可View.setOnTouchListener(View.OnTouchListener)

myView.setOnTouchListener(new SimpleTouchListener() {

    @Override
    public void onDownTouchAction() {
        // do something when the View is touched down
    }

    @Override
    public void onUpTouchAction() {
        // do something when the down touch is released on the View
    }

    @Override
    public void onCancelTouchAction() {
        // do something when the down touch is canceled
        // (e.g. because the down touch moved outside the bounds of the View
    }
});
Run Code Online (Sandbox Code Playgroud)

这是欢迎您添加到项目中的类的源代码:

public abstract class SimpleTouchListener implements View.OnTouchListener {

    /**
     * Flag determining whether the down touch has stayed with the bounds of the view.
     */
    private boolean touchStayedWithinViewBounds;

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touchStayedWithinViewBounds = true;
                onDownTouchAction();
                return true;

            case MotionEvent.ACTION_UP:
                if (touchStayedWithinViewBounds) {
                    onUpTouchAction();
                }
                return true;

            case MotionEvent.ACTION_MOVE:
                if (touchStayedWithinViewBounds
                        && !isMotionEventInsideView(view, event)) {
                    onCancelTouchAction();
                    touchStayedWithinViewBounds = false;
                }
                return true;

            case MotionEvent.ACTION_CANCEL:
                onCancelTouchAction();
                return true;

            default:
                return false;
        }
    }

    /**
     * Method which is called when the {@link View} is touched down.
     */
    public abstract void onDownTouchAction();

    /**
     * Method which is called when the down touch is released on the {@link View}.
     */
    public abstract void onUpTouchAction();

    /**
     * Method which is called when the down touch is canceled,
     * e.g. because the down touch moved outside the bounds of the {@link View}.
     */
    public abstract void onCancelTouchAction();

    /**
     * Determines whether the provided {@link MotionEvent} represents a touch event
     * that occurred within the bounds of the provided {@link View}.
     *
     * @param view  the {@link View} to which the {@link MotionEvent} has been dispatched.
     * @param event the {@link MotionEvent} of interest.
     * @return true iff the provided {@link MotionEvent} represents a touch event
     * that occurred within the bounds of the provided {@link View}.
     */
    private boolean isMotionEventInsideView(View view, MotionEvent event) {
        Rect viewRect = new Rect(
                view.getLeft(),
                view.getTop(),
                view.getRight(),
                view.getBottom()
        );

        return viewRect.contains(
                view.getLeft() + (int) event.getX(),
                view.getTop() + (int) event.getY()
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案,特别是对于在 ACTION_CANCEL 没有按应有的方式触发时处理该问题的人。 (2认同)
  • 是的,这是一个很好的答案! (2认同)