(やりたいこと)
・1つのViewでマルチタッチを処理したい
・タッチされている座標だけ把握できればおk
(やりかた)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final SparseArray<Point> touching = new SparseArray<>(); | |
view.setOnTouchListener(new OnTouchListener() { | |
@Override | |
public boolean onTouch(View view, MotionEvent motionEvent) { | |
final int actionIndex = motionEvent.getActionIndex(); | |
final int pointerId = motionEvent.getPointerId(actionIndex); | |
final int pointerIndex = motionEvent.findPointerIndex(pointerId); | |
switch (motionEvent.getActionMasked()) { | |
case MotionEvent.ACTION_DOWN: | |
case MotionEvent.ACTION_POINTER_DOWN: | |
touching.append(pointerId, new Point((int) motionEvent.getX(pointerIndex), (int) motionEvent.getY(pointerIndex))); | |
break; | |
case MotionEvent.ACTION_MOVE: | |
for (int i = 0; i < motionEvent.getPointerCount(); i++) { | |
touching.get(motionEvent.getPointerId(i)).set((int) motionEvent.getX(i), (int) motionEvent.getY(i)); | |
} | |
break; | |
case MotionEvent.ACTION_UP: | |
case MotionEvent.ACTION_POINTER_UP: | |
touching.delete(pointerId); | |
break; | |
case MotionEvent.ACTION_CANCEL: | |
touching.clear(); | |
break; | |
} | |
for (int i = 0; i < touching.size(); i++) { | |
final Point point = touching.get(touching.keyAt(i)); | |
// point.x, point.y がviewの現在のタッチされている座標 | |
} | |
} | |
}); |
(解説)
・Android SDK単品では無理そうなので、SparseArrayのテーブル(touching)を準備
・touchingテーブルは、タッチIDを主キーにタッチされている座標を記憶する
(主キーがint型なのでHashMapではなくSparseArrayを使った方が処理効率が良い)
・タッチ開始(ACTION_DOWNなど)を検出した時にテーブルにPointをadd
・移動(ACTION_MOVE)を検出した時にPointを更新
・タッチ終了(ACTION_UPなど)を検出した時にテーブルからPointをdelete
(若干疑問点)
タッチ開始(DOWN)とタッチ終了(UP)は1タッチID毎にイベント(※ここで言うイベントとはonTouchのコールバックのこと)が発生するが移動(MOVE)は2本指同時に動かした時、両方同時にイベントが発生した。
これが恒常的なもの(保証されているもの)なのかが若干疑問。
一瞬、「DOWNとUPの場合、非MASKのactionIdの9〜16bitにタッチIDが付加され、1回のイベントで取得できるactionIdは1つだから保証されているのでは?」と思ったけど、それならMOVEが1回のイベントで複数処理されるのがおかしい。
MotionEventのactionIdなんですが、明らかに設計ミスっぽい気がする(ただし、当然ですがここはプリミティブ過ぎて今更直せないという感じだろうか)。
(追記)
CANCELの場合もMOVEと同様、複数指分が纏めて走るらしいので、CANCELの時はtouchingをclearするように修正。
・Android SDK単品では無理そうなので、SparseArrayのテーブル(touching)を準備
・touchingテーブルは、タッチIDを主キーにタッチされている座標を記憶する
(主キーがint型なのでHashMapではなくSparseArrayを使った方が処理効率が良い)
・タッチ開始(ACTION_DOWNなど)を検出した時にテーブルにPointをadd
・移動(ACTION_MOVE)を検出した時にPointを更新
・タッチ終了(ACTION_UPなど)を検出した時にテーブルからPointをdelete
(若干疑問点)
タッチ開始(DOWN)とタッチ終了(UP)は1タッチID毎にイベント(※ここで言うイベントとはonTouchのコールバックのこと)が発生するが移動(MOVE)は2本指同時に動かした時、両方同時にイベントが発生した。
これが恒常的なもの(保証されているもの)なのかが若干疑問。
一瞬、「DOWNとUPの場合、非MASKのactionIdの9〜16bitにタッチIDが付加され、1回のイベントで取得できるactionIdは1つだから保証されているのでは?」と思ったけど、それならMOVEが1回のイベントで複数処理されるのがおかしい。
MotionEventのactionIdなんですが、明らかに設計ミスっぽい気がする(ただし、当然ですがここはプリミティブ過ぎて今更直せないという感じだろうか)。
(追記)
CANCELの場合もMOVEと同様、複数指分が纏めて走るらしいので、CANCELの時はtouchingをclearするように修正。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。