Androidのマルチタッチイベントと向き合う
マルチタップを制御するためのコードメモ
要点
- ポインタインデックス:MotionEvent内で管理されているタッチイベントの配列のインデックス、指が触ってから離れるまでは同じ値とは限らない。
- ポインタID:スクリーンに触っている指の識別ID、指が触ってから離れるまでは同じ値が割り当てられる。
- タッチイベントの管理:タッチイベントはMotionEvent内で配列として管理されている。MotionEvent#getPointerCountはこの配列の長さを返していると思われる。
- MotionEvent#getActionの内容:MotionEvent#getActionで取得される値は0~7ビットはアクション,8~15ビットはポインタインデックスになっている。
- アクション値の取得方法:MotionEvent#getActionとMotionEvent.ACTION_MASK(0x00ff)の積がアクション値になる。
- ポインタインデックスの取得方法:MotionEvent#getActionとMotionEvent.ACTION_POINTER_INDEX_MASK(0xff00)の積を取り、結果をさらに8ビット右シフトすることでポインタインデックスになる。
- ポインタIDの取得方法:MotionEvent#getPointerIdに対してポインタインデックスを渡すことで、対応するポインタIDを取得することができる
- DOWN系/UP系のイベントに対する処理:7で取得したポインタIDが「触れた指」または「離れた指」のポインタIDとなります。このポインタIDをMotionEvent#getX,MotionEvent#getY等に渡して値を取得する。
- MOVE系のイベントに対する処理:3で述べたようにMotionEventの中で配列として管理されているため、0からMotionEvent#getPointerCount-1の値をすべてポンタインデックスとしてすべてのタッチイベントにアクセスする必要がある。
public class MultiTouchActivity extends AppCompatActivity {
private final static int MAX_COUNT = 10;
TouchEventHolder[] touchEventHolders = new TouchEventHolder[]{
new TouchEventHolder(1),
new TouchEventHolder(2),
new TouchEventHolder(3),
new TouchEventHolder(4),
new TouchEventHolder(5),
new TouchEventHolder(6),
new TouchEventHolder(7),
new TouchEventHolder(8),
new TouchEventHolder(9),
new TouchEventHolder(10)
};
private TextView mTextView;
private StringBuilder builder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = new TextView(this);
setContentView(mTextView);
}
private void updateText() {
TouchEventHolder touchEventHolder;
builder = new StringBuilder();
for (int i = 0; i < MAX_COUNT; i++) {
touchEventHolder = touchEventHolders[i];
builder.append("ID:").append(touchEventHolder.getId()).append(", ").
append(touchEventHolder.getEventTime()).append(", ").
append(touchEventHolder.getEvent()).append(", ").
append(touchEventHolder.getX()).append(", ").
append(touchEventHolder.getY()).append("\n");
}
mTextView.setText(builder.toString());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int pointerId = event.getPointerId(pointerIndex);
TouchEventHolder touchEventHolder;
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
touchEventHolder = touchEventHolders[pointerId];
touchEventHolder.setEvent(TouchEventHolder.Event.DOWN);
touchEventHolder.setX((int) event.getX(pointerIndex));
touchEventHolder.setY((int) event.getY(pointerIndex));
touchEventHolder.setEventTime(event.getEventTime());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
touchEventHolder = touchEventHolders[pointerId];
touchEventHolder.setEvent(TouchEventHolder.Event.UP);
touchEventHolder.setX((int) event.getX(pointerIndex));
touchEventHolder.setY((int) event.getY(pointerIndex));
touchEventHolder.setEventTime(event.getEventTime());
break;
case MotionEvent.ACTION_MOVE:
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
pointerIndex = i;
pointerId = event.getPointerId(pointerIndex);
touchEventHolder = touchEventHolders[pointerId];
touchEventHolder.setEvent(TouchEventHolder.Event.MOVE);
touchEventHolder.setX((int) event.getX(pointerIndex));
touchEventHolder.setY((int) event.getY(pointerIndex));
touchEventHolder.setEventTime(event.getEventTime());
}
break;
}
updateText();
return true;
}
static class TouchEventHolder {
private int id;
private int x;
private int y;
private Event event = Event.UP;
private long eventTime;
public TouchEventHolder(int id) {
this.id = id;
}
public int getId() {
return id;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
public long getEventTime() {
return eventTime;
}
public void setEventTime(long eventTime) {
this.eventTime = eventTime;
}
public enum Event{
DOWN , MOVE , UP
}
}
}