Android2.2(API Level8)から, マルチタッチならではのピンチイン・ピンチアウトを認識するモーションジェスチャークラス(ScaleGestureDetector)が追加された.
そこで, モーションジェスチャークラスを使って, 画像をマルチタッチで拡大・縮小するプログラムを実装してみた.
1. 画像の移動
画像の移動や拡大・縮小, 回転などの画像変換を行うには, Matrixクラスを利用すると便利である.
そこで, ピンチイン・ピンチアウトによる画像の拡大・縮小を行う前に, ドラッグによる画像の移動をMatrixクラスを使って少し説明する.
画像を移動するために画面をドラッグすると, View#onTouchEventメソッドにおいて, 以下のような順にタッチイベントを取得できる. そこで, 各タッチイベントに応じて, 適宜画像の移動に必要な処理を書いていく.
具体的には,
1) ACTION_DOWNで, 現在のタッチ座標値と画像の変換行列(Matrix)を保存する.
2) ACTION_MOVEで, ACTION_DOWN時の座標からの移動量をMatrix#postTranslateメソッドに渡すことで画像変換を行う.
2. 画像の拡大・縮小[1]
画像の拡大・縮小を行うためのピンチイン・ピンチアウトを認識するためには, ScaleGestureDetectorクラスを利用する. ピンチイン・ピンチアウトの操作が行われると, ScaleGestureDetector.SimpleOnScaleGestureListenerインタフェースで, 以下のような順にメソッドが呼ばれる. そこで, 画像の移動同様に, 各メソッドで, 適宜画像の拡大・縮小に必要な処理を書いていく.
具体的には,
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で試したみた.
↓ 移動
↓ 拡大
(出典 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)ピンチイン・ピンチアウトのサンプルを作成してみる