Android2.2(API Level8)から, マルチタッチならではのピンチイン・ピンチアウトを認識するモーションジェスチャークラス(ScaleGestureDetector)が追加された.
そこで, モーションジェスチャークラスを使って, 画像をマルチタッチで拡大・縮小するプログラムを実装してみた.

1. 画像の移動
画像の移動や拡大・縮小, 回転などの画像変換を行うには, Matrixクラスを利用すると便利である.
そこで, ピンチイン・ピンチアウトによる画像の拡大・縮小を行う前に, ドラッグによる画像の移動をMatrixクラスを使って少し説明する.
画像を移動するために画面をドラッグすると, View#onTouchEventメソッドにおいて, 以下のような順にタッチイベントを取得できる. そこで, 各タッチイベントに応じて, 適宜画像の移動に必要な処理を書いていく.
Scale01
具体的には, 
  1) ACTION_DOWNで, 現在のタッチ座標値と画像の変換行列(Matrix)を保存する.
  2) ACTION_MOVEで, ACTION_DOWN時の座標からの移動量をMatrix#postTranslateメソッドに渡すことで画像変換を行う.

2. 画像の拡大・縮小[1]
画像の拡大・縮小を行うためのピンチイン・ピンチアウトを認識するためには, ScaleGestureDetectorクラスを利用する. ピンチイン・ピンチアウトの操作が行われると, ScaleGestureDetector.SimpleOnScaleGestureListenerインタフェースで, 以下のような順にメソッドが呼ばれる. そこで, 画像の移動同様に,  各メソッドで, 適宜画像の拡大・縮小に必要な処理を書いていく.

scale02
具体的には, 
  1) onScaleBeginメソッドで, 現在の画像の変換行列(Matrix)を保存する.
  2) onScaleメソッドで, onScaleBegin時からの変化(比率)を取得し, Matrix#postScaleメソッドに渡すことで画像変換を行う.

3. 動作例
[コード]
 package com.moonlight_aska.adnroid.pinchinout;

 import android.app.Activity;
 import android.content.Context;
 
import android.graphics.Matrix;
 import android.graphics.PointF;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.MotionEvent;
 
import android.view.ScaleGestureDetector;
 
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
 import android.widget.ImageView;

 public class PinchInOut extends Activity {
   // タッチの状態管理
   private static final int TOUCH_NONE   = 0;
   private static final int TOUCH_SINGLE = 1;
   private static final int TOUCH_MULTI  = 2;
   private int touchMode = TOUCH_NONE;
   // 画像処理
   private Matrix baseMatrix = new Matrix(); // タッチダウン時の画像保存用
   private Matrix imgMatrix = new Matrix(); // 画像変換用
   private PointF po0 = new PointF();   // 移動の開始点
 
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
        
     MyView view = new MyView(this);
     setContentView(view);
   }

   class MyView extends ImageView {
     private ScaleGestureDetector gesDetect = null;
  
     public MyView(Context context) {
       super(context);
       // TODO Auto-generated constructor stub
       setImageResource(R.drawable.photo);
       
setScaleType(ImageView.ScaleType.MATRIX);
       
gesDetect = new ScaleGestureDetector(context, onScaleGestureListener);
     }

     @Override
     public boolean onTouchEvent(MotionEvent event) {
       // TODO Auto-generated method stub
       int action = event.getAction() & MotionEvent.ACTION_MASK;
       int count = event.getPointerCount();
  
       
// 移動
       switch(action) {
       case MotionEvent.ACTION_DOWN:
         if(touchMode == TOUCH_NONE && count == 1) {
           Log.v("touch", "DOWN");
           
po0.set(event.getX(), event.getY());
           
baseMatrix.set(imgMatrix);
           touchMode = TOUCH_SINGLE;
         }
         break;
       case MotionEvent.ACTION_MOVE:
         if(touchMode == TOUCH_SINGLE) {
           Log.v("touch", "MOVE");
           
// 移動処理
           
imgMatrix.set(baseMatrix);
           
imgMatrix.postTranslate(event.getX() - po0.x, event.getY() - po0.y);
         }
         break;
       case MotionEvent.ACTION_UP:
         if(touchMode == TOUCH_SINGLE) {
           Log.v("touch", "UP");
           touchMode = TOUCH_NONE;
         }
         break;
       }
       if(count >= 2) {
         
gesDetect.onTouchEvent(event);
       }
       
setImageMatrix(imgMatrix);
       return true;
     }
  
     private final SimpleOnScaleGestureListener onScaleGestureListener = new SimpleOnScaleGestureListener() {

       @Override
       public boolean onScale(ScaleGestureDetector detector) {
         // TODO Auto-generated method stub
         
imgMatrix.set(baseMatrix);
         
imgMatrix.postScale(detector.getScaleFactor(), detector.getScaleFactor(),
      detector.getFocusX(), detector.getFocusY());
         return super.onScale(detector);
       }

       @Override
       public boolean onScaleBegin(ScaleGestureDetector detector) {
         // TODO Auto-generated method stub
         Log.v("touch", "onScaleBegin");
         
baseMatrix.set(imgMatrix);
         touchMode = TOUCH_MULTI;
         return super.onScaleBegin(detector);
       }

       @Override
       public void onScaleEnd(ScaleGestureDetector detector) {
         // TODO Auto-generated method stub
         Log.v("touch", "onScaleEnd");
         touchMode = TOUCH_NONE;
         super.onScaleEnd(detector);
       } 
     };
   }
 }

SH-03Cで試したみた.

pinchi01
             移動
pinchi02
             拡大
pinchi03
(出典 http://sports.livedoor.com/ )

今回は, ScaleGestureDetectorクラスを使ってピンチイン・ピンチアウトを実装したが, Android2.0(API Level 5)~Android2.2(API Level7)で実装する場合は, 「Android(X06H Desire)ピンチイン・ピンチアウトのサンプルを作成してみる」[2]のように, 自分でタッチイベントからピンチイン・ピンチアウトの認識を行う必要がある.

次は, マルチタッチによる回転操作の認識でもやってみようかな?

-----
参照URL:
 [1] ScaleGestureDetector | Android Developers
 [2] Android(X06H Desire)ピンチイン・ピンチアウトのサンプルを作成してみる