MotionEvent.ACTION_CANCEL

相変わらずACTION_UPが処理されないケースがある。
まだ何かが間違っている。それを書こうと思ったが今日はここまで。
TouchEventをGestureDetectorで置き換える

含みのある終わり方をしたが、別に大したことではない。

エミュレータデバッグしていると解らないのだが(これが大きな問題なのだが)、表題の定数で区別されるイベントが発生しており、これを処理していないのが取りこぼしている原因である。

想定されるタッチイベントの順としては、

ACTION_DOWN
↓
ACTION_MOVE..
ACTION_MOVE..
↓
ACTION_UP

となるはずだが、実際には不定期に

ACTION_DOWN
↓
ACTION_MOVE..
ACTION_MOVE..
↓
ACTION_CANCEL

となり、ジェスチャ・モーションの完了となるACTION_UPが発生しないケースがある。そのため、同アクションを期待して処理を書くと、私のように上手くいかない訳だ。

なお、最初に書いたがACTION_CANCELは実際にタッチ操作を行った場合には発生するが、マウス操作しかできないエミュレータでは発生しないため、注意が必要だ。

ACTION_CANCELに関してはリファレンスを見ると、

The current gesture has been aborted. You will not receive any more points in it. You should treat this as an up event, but not perform any action that you normally would.

とあり、何らかの理由でジェスチャが異常終了したことを示す。その後の扱いはどうにでもしてくれという感じか。

結論として、ACTION_UPと同様にACTION_CANCELでもジェスチャを検知する処理を入れることで、通常のタッチイベントでも対応できることが解った。(GestureDetectorは不要ということだ)

this.viewFlipper.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction() & 0xff; // MotionEvent.ACTION_MASK
        switch (action)  {
            case MotionEvent.ACTION_DOWN:
                lastTouchValue = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                float currentX = event.getX();
                flickOrTaptoDate(currentX, currentX - lastTouchValue);
                break;
            case MotionEvent.ACTION_CANCEL:
                currentX = event.getX();
                flickOrTaptoDate(currentX, currentX - lastTouchValue);
                break;
        }
        return  true; //detector.onTouchEvent(event);
    }
    private boolean flickOrTaptoDate(float currentX, float velocityX) {
     〜
    }

実は、GestureDetectorを止めた理由はもう一つある。GestureDetectorクラスのonFlingが検知されるには時間制限があり、それを超えるとやはりイベントとして処理しなくなってしまうから。中々うまくいかないもんだ。