7

トリガーされない場所でこの問題が発生ACTION_CANCELしています。他のプロジェクトに実装しましたが、正常に動作しています。の後に呼び出されるACTION_UPのは だけのようです。指がビュー内または画面外になくなったらトリガーしたかったのです。MotionEventACTION_DOWNACTION_CANCEL

サンプル シナリオ: LinearLayout であるビューをクリックすると、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 が処理される方法を変更したようです。

バグが発生しない特定のケースの 1 つは、ビューが のGroupLayout下にある場合ScrollViewです。スクロールが可能な場合、ACTION_CANCELが起動されます。ただし、スクロールが不可能な場合、バグは解決しません。

OnClickListener最初はandを組み合わせOnTouchListenerて、最後のアニメーションだけを処理できるようにしましたが、役に立ちませんでした。親からのイベントのディスパッチも機能しません。

1 つの回避策は、ACTION_MOVE イベントをキャプチャし、指がビューの境界の外にあるかどうかを確認するv.getX()ことv.getY()です。グローバルブール変数 ( ) を使用して、最新の情報を保存できます。を起動する前に、 の最新の状態を確認し、それに応じてアニメーションとアクションを実行できます。イベントをキャプチャしたかどうかに応じて、true または false を返すこともできます。event.getX()event.getY()isOutsideACTION_UPisOutside

更新: ここで少し掘り下げた後、私はこの解決策を見つけました: Android: Detect if user touch 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;
                }
            });
于 2013-11-23T09:14:02.017 に答える
-1
Override dispatchTouchEvent method maybe deal with it;

dimView.setOnTouchListener(新しい 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 に答える