今回は表示した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;
}