onTouch期间不会触发MotionEvent.ACTION_CANCEL

Com*_*02x 6 android ontouchlistener motionevent

我有这个问题ACTION_CANCEL没有被触发,我已经在我的其他项目中实现了它并且工作正常.似乎ACTION_UP是唯一MotionEvent被称之为的ACTION_DOWN.ACTION_CANCEL一旦我的手指不再在视野中或屏幕外,我想触发.

示例场景:我点击视图,这是一个LinearLayout btw,在ACTION_DOWN其背景上更改为图像的"单击/暗淡"版本,并且当ACTION_UP触发时,只有当手指在LinearLayout内时,其背景才会变回默认图像.现在的问题是,当我按下它并将手指放在屏幕上,并将我的手指拖到LinearLayout之外时,ACTION_UP仍然会触发它应该没有的位置.

这是我的代码:

    dimView.setOnTouchListener(new OnTouchListener() {
        public boolean onTouch(final View view,
                final MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                Log.d("TAG", "DOWN");
                return true;
            } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                Log.d("TAG", "UP");
                return true;
            } else if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
                Log.d("TAG", "CANCEL");
                return true;
            }
            return false;
        }
    });
Run Code Online (Sandbox Code Playgroud)

其中:dimView是一个LinearLayout

Tos*_*she 14

我已经调试了这个很长一段时间了,因为它非常随机地出现了很多困扰我.然后我在不同设备上测试了我的代码,并意识到Android实现了API实现的变化.Android 4.1.2(在Galaxy Tab 2上测试)的预期行为和代码工作得非常好,但是您描述的错误可以在Nexus 7(Android 4.2)上看到.显然,Android改变了在API 17中处理MotionEvent的方式.

没有发生错误的一个特殊情况是视图位于a GroupLayout下面ScrollView.当可以滚动时,ACTION_CANCEL会被触发.但是,如果无法滚动,则错误仍然存​​在.

起初我尝试组合一个OnClickListener,OnTouchListener以便最后一个只能处理动画,但无济于事.从父母调度事件也不起作用.

一个解决办法是捕捉ACTION_MOVE事件和检查手指位于使用视图的边界之外v.getX(),并v.getY()与他们进行比较event.getX()event.getY()体面.全局布尔变量(isOutside)可用于存储最新信息.在启动之前,ACTION_UP您可以检查最新状态isOutside并相应地执行动画和操作.您还可以返回true或false,具体取决于您是否捕获了事件.

更新:在这里挖了一下之后我发现了这个解决方案: Android:检测用户是否触摸并拖出按钮区域?并编译了这段代码.这个想法是相同的,除了它创建一个矩形并检查事件边界是否在视图的矩形内.

    someView.setOnTouchListener(new View.OnTouchListener() {

                private Rect rect;

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    Log.d(TAG,"Touched: "+event.getAction());
                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
                        Log.d(TAG,"ACTION_DOWN");
                        animateImageButtonOnClick(v, event);
                        rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
                    }

                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        Log.d(TAG,"ACTION_UP");
                        if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
                            Log.d(TAG,"ACTION_UP - outside");
                            animateImageButtonOnRelease(v, event);
                        }  else {
                            Log.d(TAG,"ACTION_UP - inside");
                            // do your stuff here  
                        }
                    }

                    if(event.getAction() == MotionEvent.ACTION_MOVE){
                        if(!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())){
                            animateImageButtonOnReleaseWithLowDuration(v, event);
                        }
                    }

                    if (event.getAction() == MotionEvent.ACTION_CANCEL){
                        Log.d(TAG,"ACTION_CANCEL");
                        animateImageButtonOnRelease(v, event);
                        return true;
                    }

                    return true;
                }
            });
Run Code Online (Sandbox Code Playgroud)


小智 -1

Override dispatchTouchEvent method maybe deal with it;
Run Code Online (Sandbox Code Playgroud)

dimView.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            // to call super touch method
            return false;
        }
    });

@Override
public boolean dispatchTouchEvent(MotionEvent motionEvent) {
    // TODO Auto-generated method stub
    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
        Log.d("TAG", "DOWN");
        return true;
    } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
        Log.d("TAG", "UP");
        return true;
    } else if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
        Log.d("TAG", "CANCEL");
        return true;
    }
    return super.dispatchTouchEvent(motionEvent);
}
Run Code Online (Sandbox Code Playgroud)