Androidプログラマへの道 〜 Moonlight 明日香 〜 - マルチタッチイベントを取得する
Android 2.0(API 5)以降でマルチタッチ(Multi-touch)がサポートされた.
複数の指でタッチパネルを操作すると, タッチイベント(Touch Event)がACTION_DOWN/ACTION_POINTER_DOWN→ACTION_MOVE(繰返し)→ACTION_UP/ACTION_POINTER_UPの順に発生する.
ACTION_POINTER_DOWNは, 画面の1点以上をタッチしている状態で, さらに画面にタッチした際に発生する. また, ACTION_POINTER_UPは, 画面の2点以上をタッチしている状態で, その内の1点を離した際に発生する.
マルチタッチのタッチイベントを取得するには, タッチイベントを取得すると同様にonTouchEventメソッドをオーバーライドする.

アクティビティで取得する

    • Activity#onTouchEventメソッドをオーバーライドする.
    • MotionEvent#getActionメソッドで, タッチアクション情報を取得する.
    • MotionEvent#getPointerCountメソッドで, タッチ座標点数を取得する.
    • タッチアクション情報をMotionEvent.ACTION_POINTER_ID_MASKでマスクし, MotionEvent.ACTION_POINTER_ID_SHIFT分シフトすることで, ポインタIDを取得するためのインデックスを取得する.
    • タッチアクション情報をMotionEvent.ACTION_MASKでマスクし, タッチアクションを取得する.
    • MotionEvent#getXメソッド, getYメソッドで, タッチされたx, y座標を取得する.
    • MotionEvent#getPointerIdメソッドで, ポインタIDを取得する.
package com.moonlight_aska.android.multitouch01;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;

public class MultiTouch01 extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    int action = event.getAction();
    int count = event.getPointerCount();
    int id = (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;

    switch(action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
      Log.v("Multi", "Touch Down" + " count=" + count + ", id=" + id);
      break;
    case MotionEvent.ACTION_POINTER_DOWN:
      Log.v("Multi", "Touch PTR Down" + " count=" + count + ", id=" + id);
      break;
    case MotionEvent.ACTION_UP:
      Log.v("Multi", "Touch Up" + " count=" + count + ", id=" + id);
      break;
    case MotionEvent.ACTION_POINTER_UP:
      Log.v("Multi", "Touch PTR Up" + " count=" + count + ", id=" + id);
      break;
    case MotionEvent.ACTION_MOVE:
      Log.v("Multi", "Touch Move" + " count=" + count + ", id=" + id);
      break;
    }
    for(int i=0; i<count; i++) {
      Log.v("Multi", " X=" + event.getX(i) + ", Y=" + event.getY(i) + ", id=" + event.getPointerId(i) );
    }
    return super.onTouchEvent(event);
  }
}


Viewで取得する

    • View#onTouchEventメソッドをオーバーライドする.
    • MotionEvent#getPointerCountメソッドで, タッチ座標点数を取得する.
    • MotionEvent#getPointerIdメソッドで, ポインタIDを取得する.
    • MotionEvent#getXメソッド, getYメソッドで, タッチされたx, y座標を取得する.
package com.moonlight_aska.android.multitouch02;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;

public class MultiTouch02 extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    MyView view = new MyView(this);
    setContentView(view);
  }

  class MyView extends View {
    final static int MULTI_TOUCH_MAX = 5;
    private PointF [] points = new PointF[MULTI_TOUCH_MAX];
    private int[] color = {Color.BLUE, Color.CYAN, Color.GREEN, Color.RED, Color.YELLOW};

    public MyView(Context context) {
      super(context);
      setBackgroundColor(Color.WHITE);
      setFocusable(true);

      for(int i=0; i<MULTI_TOUCH_MAX; i++) {
        points[i] = new PointF(-1.0F, -1.0F);
      }
    }

    @Override
    protected void onDraw(Canvas canvas) {
      // TODO Auto-generated method stub
      Paint paint = new Paint();
      paint.setAntiAlias(true);
      paint.setStyle(Paint.Style.FILL_AND_STROKE);
      // タッチ位置の描画
      for(int i=0; i<MULTI_TOUCH_MAX; i++) {
        if(points[i].x < 0.0 && points[i].y < 0.0)
          continue;
        paint.setColor(color[i]);
        canvas.drawCircle(points[i].x, points[i].y, 20, paint);
      }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
      // TODO Auto-generated method stub
      int count = event.getPointerCount();
      for(int i=0; i<count; i++) {
        int id = event.getPointerId(i);
        points[id].x = event.getX(i);
        points[id].y = event.getY(i);
      }
      invalidate();
      return true;
    }
  }
}

以下は, SH-03C(NTT Docomo)で動作させた例である.
SH-03や003SH(Softbank)で試したところ, 最大5つのタッチまで判定できた.