7

我在ACTION_CANCEL没有触发的地方遇到了这个问题,我已经在我的另一个项目中实现了它并且它工作正常。似乎这ACTION_UP是唯一MotionEvent被调用的ACTION_DOWNACTION_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 是一个 LinearLayout

4

2 回答 2

17

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

GroupLayout不发生错误的一种特殊情况是视图位于ScrollView. 当滚动是可能的ACTION_CANCEL被解雇。但是,当无法滚动时,错误仍然存​​在。

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

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

更新:在这里挖掘了一下之后,我找到了这个解决方案: 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;
                }
            });
于 2013-11-23T09:14:02.017 回答
-1
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);
}
于 2013-10-17T03:24:44.160 回答