[Android]ビュアーもどきズーム機能を...
Posted: 2013年6月22日(土) 19:31
お久しぶりです、ひよつこです。
今回もお世話になります。
現在開発中のビュアーもどきアプリに本格的にズーム機能を付けよう思っています。
そこでView.OnTouchListenerを継承した拡大率と移動したx,y座標を返すリスナーを作りました。
下のコードはそれを実装したカスタムビューのコードです。
といった感じのコードになりました。
しかしこのリスナーを実装してからの処理がわかりません。
受け取った引数を元にMatrixを作成し、カスタムビューに設定したいのですが、
具体的にどのようにMatrixを使えばいいのでしょうか。
リスナーの方に問題がある場合もご指摘よろしくお願いします。
今回もお世話になります。
現在開発中のビュアーもどきアプリに本格的にズーム機能を付けよう思っています。
そこでView.OnTouchListenerを継承した拡大率と移動したx,y座標を返すリスナーを作りました。
下のコードはそれを実装したカスタムビューのコードです。
private CustomListener vListener;
private float pinchStartDistance = 0.0f;
private PointF pinchStartPoint = new PointF();
private float totalScale = 1.0f;
private PointF totalMove = new PointF();
private int touchMode = TOUCH_NONE;
private static final int TOUCH_NONE = 0;
private static final int TOUCH_DRAG = 1;
private static final int TOUCH_ZOOM = 2;
private static final int TOUCH_FLICK = 3;
public final boolean TURN_RIGHT = true;
public final boolean TURN_LEFT = false;
public final boolean TOUCHED_NOW = true;
public final boolean TOUCHED_FINISH = false;
private View.OnTouchListener tListener = new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
//ピンチ操作でズーム処理をする
switch(event.getAction() & MotionEvent.ACTION_MASK){
//ピンチ操作開始
case MotionEvent.ACTION_POINTER_DOWN:
if(event.getPointerCount() >= 2){
pinchStartDistance = getDistance(event);
if(pinchStartDistance > 50f){
pinchStartPoint = getCenterPoint(event);
totalMove.x += pinchStartPoint.x * totalScale;
totalMove.y += pinchStartPoint.y * totalScale;
touchMode = TOUCH_ZOOM;
}
}
break;
//ピンチ操作中
case MotionEvent.ACTION_MOVE:
if(touchMode == TOUCH_ZOOM && pinchStartDistance > 0){
float scale = 1.0f;
scale = getDistance(event) / pinchStartDistance;
scale *= totalScale;
vListener.onPageZoom(totalMove.x,totalMove.y,scale,false);
}
break;
//ピンチ操作終了
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if(touchMode == TOUCH_ZOOM){
totalScale = getDistance(event) / pinchStartDistance * totalScale;
pinchStartPoint.x = 0.0f;
pinchStartPoint.y = 0.0f;
if(totalScale < 1.0f){
totalScale = 1.0f;
totalMove.x = totalMove.y = 0.0f;
touchMode = TOUCH_NONE;
}
vListener.onPageZoom(totalMove.x, totalMove.y, totalScale, true);
}
}
//ズーム中にドラッグ操作をするとビュアーをスライドする...のが目的
switch(event.getAction() & MotionEvent.ACTION_MASK){
//ドラッグ操作開始
case MotionEvent.ACTION_DOWN:
if(touchMode == TOUCH_ZOOM & event.getPointerCount() == 1){
pinchStartPoint.x = event.getX();
pinchStartPoint.y = event.getY();
touchMode = TOUCH_DRAG;
}
break;
//ドラッグ操作中
case MotionEvent.ACTION_MOVE:
if(touchMode == TOUCH_DRAG){
float moveX = totalMove.x - (event.getX() - pinchStartPoint.x);
float moveY = totalMove.y - (event.getY() - pinchStartPoint.y);
vListener.onPageDrag(moveX, moveY, false);
}
break;
//ドラッグ操作終了
case MotionEvent.ACTION_UP:
if(touchMode == TOUCH_DRAG){
totalMove.x = totalMove.x - (event.getX() - pinchStartPoint.x);
totalMove.y = totalMove.y - (event.getY() - pinchStartPoint.y);
touchMode = TOUCH_ZOOM;
if(totalMove.x < 0.0f){
totalMove.x = 0.0f;
}else if(totalMove.x > viewerWidth){
totalMove.x = viewerWidth;
}
if(totalMove.y < 0.0f){
totalMove.y = 0.0f;
}else if(totalMove.y > viewerHeight){
totalMove.y = viewerHeight;
}
vListener.onPageDrag(totalMove.x, totalMove.y, true);
}
}
//フリック操作でビュアーのページを更新
switch(event.getAction() & MotionEvent.ACTION_MASK){
//フリック操作開始
case MotionEvent.ACTION_DOWN:
if(touchMode == TOUCH_NONE & event.getPointerCount() == 1){
pinchStartPoint.x = event.getX();
touchMode = TOUCH_FLICK;
}
break;
//フリック操作終了
case MotionEvent.ACTION_UP:
if(touchMode == TOUCH_FLICK){
if(event.getX() - pinchStartPoint.x < - viewerWidth / 2){
vListener.onTurnPage(TURN_RIGHT); //左向きにページめくり
}else if(event.getX() - pinchStartPoint.x > viewerWidth / 2){
vListener.onTurnPage(TURN_LEFT); //右向きにページめくり
}
touchMode = TOUCH_NONE;
}
break;
}
return true;
}
};
//ピンチ距離取得用
private float getDistance(MotionEvent event) {
if(event.getPointerCount() > 1){
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);
}else{
return pinchStartDistance;
}
}
//ピンチ開始座標取得用
private PointF getCenterPoint(MotionEvent event) {
PointF pt = pinchStartPoint;
if(event.getPointerCount() > 1){
pt.x = (event.getX(0) + event.getX(1)) * 0.5f;
pt.y = (event.getY(0) + event.getY(1)) * 0.5f;
}
return pt;
}
しかしこのリスナーを実装してからの処理がわかりません。
受け取った引数を元にMatrixを作成し、カスタムビューに設定したいのですが、
具体的にどのようにMatrixを使えばいいのでしょうか。
リスナーの方に問題がある場合もご指摘よろしくお願いします。