2017年5月6日土曜日

View.OnTouchListenerでのマルチタッチ処理

やりたいことはシンプルなのに実装が色々と面倒臭かったので、備忘録を兼ねてメモ。

(やりたいこと)
・1つのViewでマルチタッチを処理したい
・タッチされている座標だけ把握できればおk

(やりかた)

(解説)
・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するように修正。