今回は表示したJPEG画像をピンチ操作によりズームする。ピンチ操作というのは2本の指で画面をタッチして、指間隔を開けば拡大、指間隔を狭めれば縮小というもの。
まずはEasyProjectGenerator for Androidで雛形になるプロジェクトを作成。

package com.Test131; import android.app.Activity; import android.os.Bundle; import android.widget.LinearLayout; public class Test131Act extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout layout = new LinearLayout(this); setContentView(layout); ImageFileView view = new ImageFileView(this); layout.addView(view); } }
ImageFileView.javaというファイルを作り、実装する。
package com.Test131; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.view.View; public class ImageFileView extends View { //表示画像 protected Bitmap _bmpImageFile; public ImageFileView(Context context) { super(context); { String strFile = "/sdcard/DSC_0670.JPG"; _bmpImageFile = LoadImageFile(strFile,800*2); } } public Bitmap LoadImageFile(String strFile,int nMaxWidth) { Bitmap bmpImage; //画像の解析(大きい画像が開けない対策) BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(strFile,options); int nWidth = options.outWidth; int nHeight = options.outHeight; if(nWidth == 0 || nHeight == 0) return null; if(nWidth <= nMaxWidth && nHeight <= nMaxWidth) { //リサイズ不要。そのまま読み込んで返す options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(strFile,options); } int nScale; //nScaleは2の乗数にする { float fScale; float fScaleX = (float)nWidth / nMaxWidth; float fScaleY = (float)nHeight / nMaxWidth; fScale = (fScaleX > fScaleY) ? fScaleX : fScaleY; nScale = 1; while(fScale >= nScale) { nScale *= 2; } } //画像の本読み込み options.inJustDecodeBounds = false; options.inSampleSize = nScale; bmpImage = BitmapFactory.decodeFile(strFile,options); return bmpImage; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(_bmpImageFile == null) return; Matrix matrix = new Matrix(); //描画 canvas.drawBitmap(_bmpImageFile, matrix, null); } }

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(_bmpImageFile == null) return; //画面表示用ズーム率 float fImageScale; //余白 float fMarginX = 0.0f; float fMarginY = 0.0f; //ズーム率取得 { int nImageWidth = _bmpImageFile.getWidth(); int nImageHeight= _bmpImageFile.getHeight(); int nViewWidth = getWidth(); int nViewHeight = getHeight(); //画像に合わせる if((long)nImageWidth * nViewHeight > (long)nViewWidth * nImageHeight) { fImageScale = (float)nViewWidth / nImageWidth; fMarginY = (nViewHeight - fImageScale * nImageHeight) * 0.5f; } else { fImageScale = (float)nViewHeight / nImageHeight; fMarginX = (nViewWidth - fImageScale * nImageWidth) * 0.5f; } } //ズーム率 float fScale = fImageScale; //余白移動 float fMoveX = fMarginX; float fMoveY = fMarginY; Matrix matrix = new Matrix(); //ズーム matrix.preScale(fScale,fScale); //移動 matrix.postTranslate(fMoveX,fMoveY); //描画 canvas.drawBitmap(_bmpImageFile, matrix, null); }
これで画像に合わせて縮小&余白表示された。ここまではこれまでも紹介してきた流れで、ピンチ操作などは実装していない。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(_bmpImageFile == null) return; //画面表示用ズーム率 float fImageScale; //余白 float fMarginX = 0.0f; float fMarginY = 0.0f; //ズーム率取得 { int nImageWidth = _bmpImageFile.getWidth(); int nImageHeight= _bmpImageFile.getHeight(); int nViewWidth = getWidth(); int nViewHeight = getHeight(); //画像に合わせる if((long)nImageWidth * nViewHeight > (long)nViewWidth * nImageHeight) { fImageScale = (float)nViewWidth / nImageWidth; fMarginY = (nViewHeight - fImageScale * nImageHeight) * 0.5f; } else { fImageScale = (float)nViewHeight / nImageHeight; fMarginX = (nViewWidth - fImageScale * nImageWidth) * 0.5f; } } //ピンチを含めた総合ズーム率 float fScale = _fPinchScale * fImageScale; //余白を含めた移動量 float fMoveX = _fPinchMoveX + fMarginX; float fMoveY = _fPinchMoveY + fMarginY; //ズーム原点指定 fMoveX += _ptPinchStart.x - _ptPinchStart.x * _fPinchScale; fMoveY += _ptPinchStart.y - _ptPinchStart.y * _fPinchScale; Matrix matrix = new Matrix(); //ズーム matrix.preScale(fScale,fScale); //移動 matrix.postTranslate(fMoveX,fMoveY); //描画 canvas.drawBitmap(_bmpImageFile, matrix, null); } //ピンチによる現在のズーム率(拡大 > 1.0f > 縮小) private float _fPinchScale = 1.0f; private PointF _ptPinchStart = new PointF(); private float _fPinchStartDistance = 0.0f; private float _fPinchMoveX = 0.0f; private float _fPinchMoveY = 0.0f; //タッチ操作内部処理用 private static final int TOUCH_NONE = 0; private static final int TOUCH_DRAG = 1; private static final int TOUCH_ZOOM = 2; private int _nTouchMode = TOUCH_NONE; @Override public boolean onTouchEvent(MotionEvent event) { switch(event.getAction() & MotionEvent.ACTION_MASK) { //ピンチ開始 case MotionEvent.ACTION_POINTER_DOWN: if(event.getPointerCount() >= 2) { _fPinchStartDistance = GetDistance(event); if(_fPinchStartDistance > 50f) { GetCenterPoint(event,_ptPinchStart); _nTouchMode = TOUCH_ZOOM; } } break; //ピンチ中 case MotionEvent.ACTION_MOVE: if(_nTouchMode == TOUCH_ZOOM && _fPinchStartDistance > 0) { PointF pt = new PointF(); GetCenterPoint(event,pt); _fPinchMoveX = pt.x - _ptPinchStart.x; _fPinchMoveY = pt.y - _ptPinchStart.y; _fPinchScale = GetDistance(event) / _fPinchStartDistance; invalidate(); } break; //ピンチ終了 case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: if(_nTouchMode == TOUCH_ZOOM) { //ピンチ終了処理 _nTouchMode = TOUCH_NONE; _fPinchMoveX = 0.0f; _fPinchMoveY = 0.0f; _fPinchScale = 1.0f; _ptPinchStart.x = 0.0f; _ptPinchStart.y = 0.0f; invalidate(); } break; } switch(event.getAction() & MotionEvent.ACTION_MASK) { //ドラッグ開始 case MotionEvent.ACTION_DOWN: if(_nTouchMode == TOUCH_NONE && event.getPointerCount() == 1) { _nTouchMode = TOUCH_DRAG; } break; case MotionEvent.ACTION_MOVE: if(_nTouchMode == TOUCH_DRAG) { } break; //ドラッグ終了 case MotionEvent.ACTION_UP: if(_nTouchMode == TOUCH_DRAG) { //ドラッグ終了処理 _nTouchMode = TOUCH_NONE; break; } } return true; } //ピンチ距離取得用 private float GetDistance(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return android.util.FloatMath.sqrt(x * x + y * y); } //ピンチ開始座標取得用 private void GetCenterPoint(MotionEvent event,PointF pt) { pt.x = (event.getX(0) + event.getX(1)) * 0.5f; pt.y = (event.getY(0) + event.getY(1)) * 0.5f; }
プロジェクトファイルをダウンロード