はじめに
Androidでマルチタッチを使う方法を記載します。
タッチイベントの取得
タッチパネルを触るとonTouchEvent()がコールされます。
Activity or Viewでこの関数をoverrideすることでイベントを取得できます。
イベントはonTouchEvent()の引数MotionEventに格納されます。
イベントには種別があり、これをアクションといいます。
アクションはgetActionMasked()で取得します。
アクションの種類
アクションには次のものがあります。
タッチしていない状態でタッチしたとき
- ACTION_DOWN
- 0x00000000
タッチしている状態でタッチしなくなったとき
- ACTION_UP
- 0x00000001
すでにタッチしている状態で追加タッチしたとき
例えばある指でタッチしている状態で、別の指でタッチしたとき
- ACTION_POINTER_DOWN
- 0x00000005
複数の指でタッチしている状態で、そのうち1つの指を離したときのイベント
- ACTION_POINTER_UP
- 0x00000006
タッチ中に指を動かした場合
- ACTION_MOVE
- 0x00000002
何らかの要因でキャンセルされた場合、ACTION_UPと同じ扱いにした方がいい。
- ACTION_CANCEL
- 0x00000003
複数タッチの識別方法
Pointer indexとData index
複数のタッチがあるときに、それぞれのタッチを識別するために、
タッチには識別子Pointer indexがついています。
タッチ開始時(触った時)に付与されて、タッチ終了時(離したとき)になくなります。
一方でMotionEvent内に格納されたデータには配列のindexがあります。
これをData indexということにします。
少しわかりにくいので例で説明します。
Data indexは配列のindexなので、0から始まります、1つずつ増加して、(Data配列サイズ-1)で終わります。
Pointer indexはタッチの識別子です。複数の指で触ったり、離したりすることを考えると、順番はバラバラになることがあります。
また、値が(Data配列サイズ-1)を超える場合もあります。x,yは各タッチの座標値です。
Pointer index, 座標値の取得
Pointer index,座標値の取得方法は次の通りです。
// 注意 : 説明のための必要最小限のソースコードに切り出しているため、実行はできません。
MotionEvent event;
int count = event.getPointerCount();
for (int i=0; i<count; i++) {
int pid = event.getPointerId(i);
float x = event.getX(i);
float y = event.getY(i);
}
タッチしている数(Data配列のサイズ)をgetPointerCount()で取得します。Data indexでループします。
Pointer indexは引数をData indexとしてgetPointerId()で取得します。
座標値はgetX(),getY()で取得します。
Pointer indexを指定してData indexを取得する
あるPointer indexが、どのData indexに対応しているかを知るにはfindPointerIndex(Pointer index)を使います。
引数にPointer indexを指定すると戻り値にData indexが返ってきます。
蓄積されたイベント
処理負荷が増加すると、あるonTouchEvent()と次のonTouchEvent()の間に、
複数回タッチイベントが発生することがあります。下図参照。
例:
この時、複数のタッチイベントはMotionEvent内に蓄積されます。
後ろ側のonTouchEventで蓄積された(例ではA)タッチイベントと現在のタッチイベント(例ではB)が取得できます。
蓄積されたタッチイベントの個数はgetHistorySize()で取得できます。
例ではタッチイベントAが1つ蓄積されるので値1が取得されます。
蓄積された座標データはgetHistoricalX(Data index, index), getHistoricalY(Data index, index)で取得できます。
第2引数は0~(getHistorySize()-1)の値です。index値が小さいほど古いデータになります。
@Override
public boolean onTouchEvent(MotionEvent event) {
int count = event.getPointerCount();
for (int i=0; i<count; i++) {
float x = event.getX(i);
float y = event.getY(i);
int hsize = event.getHistorySize();
for (int j=0; j<hsize; j++) {
float hx = event.getHistoricalX(i, j);
float hy = event.getHistoricalY(i, j);
}
}
return true;
}
サンプルソースコード
@Override
public boolean onTouchEvent(MotionEvent event) {
int action1 = event.getAction();
int action2 = event.getActionMasked();
int count = event.getPointerCount();
Log.e("", "getAction=0x" + String.format("%04x", action1) + ",getActionMasked=0x" + String.format("%04x", action2)
+ ",getPointerCount=" + count);
for (int i=0; i<count; i++) {
int pid = event.getPointerId(i);
int id = event.findPointerIndex(pid);
if (id == -1)
continue;
float x = event.getX(id);
float y = event.getY(id);
float p = event.getPressure(id);
float s = event.getSize(id);
int hsize = event.getHistorySize();
String line = "\t";
line += "getPointerId=" + pid + ",";
line += "getHistorySize=" + hsize + ",";
for (int j=0; j<hsize; j++) {
float hx = event.getHistoricalX(id, j);
float hy = event.getHistoricalY(id, j);
float hp = event.getHistoricalPressure(id, j);
float hs = event.getHistoricalSize(id, j);
line += "x=" + String.format("%.2f", hx) + ",";
line += "y=" + String.format("%.2f", hy) + ",";
line += "p=" + String.format("%.4f", hp) + ",";
line += "s=" + String.format("%.4f", hs) + ",";
}
line += "x=" + String.format("%.2f", x) + ",";
line += "y=" + String.format("%.2f", y) + ",";
line += "p=" + String.format("%.4f", p) + ",";
line += "s=" + String.format("%.4f", s) + ",";
Log.e("", line);
}
return true;
//return super.onTouchEvent(event);
}
Appendix
getAction()とgetActionMasked()の違い
getAction()とgetActionMasked()の違いを説明します。
シングルタッチの場合、両者で取得されるイベントは同じになります。
マルチタッチの場合、違いがあります。
getAction()で取得されるイベントにはPointer indexが付加されます。
getActionMasked()で取得されるイベントはPointer indexがマスクされたものです。
具体例で説明します。
シングルタッチでタップしたときのアクションです。
双方同じ値が取得されます。
D/: getAction=0x0000,getActionMasked=0x0000
D/: getAction=0x0002,getActionMasked=0x0002
D/: getAction=0x0002,getActionMasked=0x0002
D/: getAction=0x0002,getActionMasked=0x0002
D/: getAction=0x0001,getActionMasked=0x0001
マルチタッチの例として、
1本目の指でタッチ後、2本目の指でタッチし、指2→指1の順番で指を離したときのアクションで説明します。
2本目をタッチしたときと、2本目を離したとき(*箇所)、
getAction()とgetActionMasked()で取得されるアクションに違いがあることが分かります。
getAction()で取得されるアクションにはPointer indexも一緒に渡されます。
具体的には2本目の指をタッチしたとき、アクションは0x0105となり0x01の部分は2本目を表します。
getActionMasked()が返すアクションはPointer indexがマスクされたものになります。
D/: getAction=0x0000,getActionMasked=0x0000
D/: getAction=0x0002,getActionMasked=0x0002
D/: getAction=0x0002,getActionMasked=0x0002
D/: getAction=0x0105,getActionMasked=0x0005(*)
D/: getAction=0x0002,getActionMasked=0x0002
D/: getAction=0x0002,getActionMasked=0x0002
D/: getAction=0x0106,getActionMasked=0x0006(*)
D/: getAction=0x0001,getActionMasked=0x0001