読者です 読者をやめる 読者になる 読者になる

<!--親の顔より見た光景-->

日々の発見を残していきます。

【Android】onLongPressを使わないで長押し判定

背景

View上で長押しを判定したい時、通常はGestureDetectorクラスのOnGestureListenerをimplementsしてonLongPressを実装する。
GestureDetector | Android Developers

参考サイト
Androidプログラミングの館
Android タッチパネルのダブルタップや長押しを検出する方法 | TechBooster

しかしonLongPressは長押し判定の時間を指定できない。

今作ってるマインスイーパアプリでは長押しでフラグを立てる処理にしている。
onLongPressで長押し判定を実装すると、0.8秒程度押し続けないとならない。
0.8秒という時間は長く、ユーザーはスピーディーにフラグを立てることができなくてイライラしてしまう。

解決策

onTouchEventで取得できるMotionEvent.ACTION_DOWNとHandlerクラスを使う。

onTouchEventはViewクラスで画面がタッチされたときに呼び出されるメソッド。
詳しくはこちら
Androidでアプリ画面のタッチイベントを取得する方法 | TechBooster

Handlerクラスは「指定した時間後に処理を行いたい」という時に使い、処理の中身はRunnableクラスのrun()メソッドで実装する。
詳しくはこちら
[Android]指定した時間後にちょっとした処理を行う方法 | Developers.IO

結局長押し判定はこんなコードになる。convertCoordinateToAddress()は現在の座標からマス番号を求めるメソッド。
とりあえずACTION_DOWNが検出されたらhandlerを起動して、0.4秒後にrunメソッドを実行する。
0.4秒を測ってる間に指上げなどの邪魔が入ったらhandlerを中止する。

参考サイト
java - Detecting a long press with Android - Stack Overflow

【MainActivity.java

/*略*/
long LONG_PRESS_TIME = 400;    // 長押し時間(ミリ秒)
Handler long_press_handler = new Handler();
Runnable long_press_receiver = new Runnable() {
    @Override
    public void run()
    {
        // 長押しする
        longClickSquare();
    }
};

/*略*/
@Override
public boolean onTouchEvent( MotionEvent e )
{
    switch ( e.getAction() )
    {
        case MotionEvent.ACTION_DOWN:    // 指が触れたとき
            action_down_square_address = game_view.convertCoordinateToAddress(e.getX(), e.getY());       // 触れたマス番号を記憶
            long_press_handler.postDelayed( long_press_receiver, LONG_PRESS_TIME);       // 長押し判定
            break;

        case MotionEvent.ACTION_UP:     // 指を上げたとき
            long_press_handler.removeCallbacks( long_press_receiver );    // 長押し中に指を上げたらhandlerの処理を中止
            break;

        case MotionEvent.ACTION_MOVE :    // 指でなぞったとき
            // 触れたマスが最初に触れていたマスと違う番号なら
            if ( game_view.convertCoordinateToAddress(e.getX(), e.getY()) != action_down_square_address ) {
                long_press_handler.removeCallbacks( long_press_receiver );    // 最初に触れたマスから離れたらhandlerの処理を中止
            }
            break;

        default:
            break;
        }
        return false;
    }
}

/*略*/