package com.example.android.recipe060;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
public class TouchImageView extends ImageView {
// 現在の状態のMatrix
// これがタッチイベントのたびに変化する
private Matrix mMatrix = new Matrix();
// 前の状態を保持するためのMatrix
// postTranslateが相対座標で扱われるため
// 前の状態を保持しておいて、setでベースとしてセットする
private Matrix mSavedMatrix = new Matrix();
// 状態フラグ
private static final int NONE = 0; // 何もしてない
private static final int DRAG = 1; // ドラッグ中
private static final int ZOOM = 2; // ズーム中
// 現在の状態
private int mMode = NONE;
// ドラッグ開始座標を保持する
private PointF mStartPoint = new PointF();
// ズーム開始時の距離を保持する
private float mOldDistance;
// ズーム開始時の中点座標を保持する
private PointF mMidPoint = new PointF();
public TouchImageView(Context context) {
super(context);
init(context);
}
public TouchImageView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
// 初期化
private void init(Context context) {
// クリックできるように
setClickable(true);
// Matrixを使ってスケールする
setScaleType(ScaleType.MATRIX);
// OnTouchListenerをセット
setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// タッチ開始(ドラッグ開始)
case MotionEvent.ACTION_DOWN:
mMode = DRAG;
mStartPoint.set(event.getX(), event.getY());
mSavedMatrix.set(mMatrix);
break;
// タッチが移動している状態
// ドラッグ中とズーム中で処理を切り替える
case MotionEvent.ACTION_MOVE:
if(mMode == DRAG) {
mMatrix.set(mSavedMatrix);
float x = event.getX() - mStartPoint.x;
float y = event.getY() - mStartPoint.y;
mMatrix.postTranslate(x, y);
} else if (mMode == ZOOM) {
float newDist = culcDistance(event);
float scale = newDist / mOldDistance;
mMatrix.set(mSavedMatrix);
mMatrix.postScale(scale, scale,
mMidPoint.x, mMidPoint.y);
}
break;
// タッチ終了
case MotionEvent.ACTION_UP:
mMode = NONE;
break;
// マルチタッチ開始(ズーム開始)
case MotionEvent.ACTION_POINTER_DOWN:
mMode = ZOOM;
mOldDistance = culcDistance(event);
culcMidPoint(mMidPoint, event);
break;
// マルチタッチ終了(ズーム終了)
case MotionEvent.ACTION_POINTER_UP:
mMode = NONE;
break;
default:
break;
}
// postTranslateメソッドで座標
// postScaleメソッドでスケール
// が変化したMatrixをImageに反映させる。
setImageMatrix(mMatrix);
return true;
}
});
}
// マルチタッチの2点間の距離を計算して返します。
private float culcDistance(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
// マルチタッチの2点間の中点座標を計算してmidPointにセットします。
private void culcMidPoint(PointF midPoint, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
midPoint.set(x / 2, y / 2);
}
}