【问题标题】:MotionEvent.ACTION_CANCEL is not triggered during onTouch在 onTouch 期间未触发 MotionEvent.ACTION_CANCEL
【发布时间】:2013-10-17 03:13:00
【问题描述】:

我遇到了这个问题,ACTION_CANCEL 没有被触发,我已经在我的另一个项目中实现了它,它工作正常。似乎ACTION_UP 是在ACTION_DOWN 之后调用的唯一MotionEvent。一旦我的手指不在视图中或屏幕外,我想触发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;
        }
    });

其中:dimView 是一个线性布局

【问题讨论】:

    标签: android ontouchlistener motionevent


    【解决方案1】:

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

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

    起初我尝试将OnClickListenerOnTouchListener 组合在一起,以便最后一个可以只处理动画,但无济于事。从父母那里分派事件也不起作用。

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

    更新:在这里挖掘了一下后,我找到了这个解决方案: Android: Detect if user touches and drags out of button region? 并编译了这段代码。这个想法是一样的,只是它创建一个矩形并检查事件边界是否在视图的矩形内。

        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;
                    }
                });
    

    【讨论】:

      【解决方案2】:
      Override dispatchTouchEvent method maybe deal with it;
      

      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);
      }
      

      【讨论】:

      • 不过,MotionEvent.ACTION_CANCEL 在测试期间仍未触发。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-16
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多