Androidのピンチズームにスケールジェスチャ検出器を使用できますか?
6 に答える
これを使用できます
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
public class MyImageView extends View {
private static final int INVALID_POINTER_ID = -1;
private Drawable mImage;
private float mPosX;
private float mPosY;
private float mLastTouchX;
private float mLastTouchY;
private int mActivePointerId = INVALID_POINTER_ID;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
public MyImageView(Context context) {
this(context, null, 0);
mImage=act.getResources().getDrawable(context.getResources().getIdentifier("imagename", "drawable", "packagename"));
mImage.setBounds(0, 0, mImage.getIntrinsicWidth(), mImage.getIntrinsicHeight());
}
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
mImage.draw(canvas);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
invalidate();
return true;
}
}
}
これをあなたのactivity.setContentView(new MyImageView(this));
これを実現するために実装する再利用可能なクラスを作成できますOnTouchListener
。
public class MyScaleGestures implements OnTouchListener, OnScaleGestureListener {
private View view;
private ScaleGestureDetector gestureScale;
private float scaleFactor = 1;
private boolean inScale = false;
public MyScaleGestures (Context c){ gestureScale = new ScaleGestureDetector(c, this); }
@Override
public boolean onTouch(View view, MotionEvent event) {
this.view = view;
gestureScale.onTouchEvent(event);
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = (scaleFactor < 1 ? 1 : scaleFactor); // prevent our view from becoming too small //
scaleFactor = ((float)((int)(scaleFactor * 100))) / 100; // Change precision to help with jitter when user just rests their fingers //
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
inScale = true;
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) { inScale = false; }
}
View
次に、それをあなたのOnTouchListener
ように割り当てます。
myView.setOnTouchListener(new MyScaleGestures(context));
にスクロール機能を追加する場合は、インターフェイスView
から実装する必要があります。これを実現するために、このオーバーライドをクラスに追加できます。onScroll
OnGestureListener
MyScaleGestures
@Override
public boolean onScroll(MotionEvent event1, MotionEvent event2, float x, float y) {
float newX = view.getX();
float newY = view.getY();
if(!inScale){
newX -= x;
newY -= y;
}
WindowManager wm = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
Point p = new Point();
d.getSize(p);
if (newX > (view.getWidth() * scaleFactor - p.x) / 2){
newX = (view.getWidth() * scaleFactor - p.x) / 2;
} else if (newX < -((view.getWidth() * scaleFactor - p.x) / 2)){
newX = -((view.getWidth() * scaleFactor - p.x) / 2);
}
if (newY > (view.getHeight() * scaleFactor - p.y) / 2){
newY = (view.getHeight() * scaleFactor - p.y) / 2;
} else if (newY < -((view.getHeight() * scaleFactor - p.y) / 2)){
newY = -((view.getHeight() * scaleFactor - p.y) / 2);
}
view.setX(newX);
view.setY(newY);
return true;
}
上記のすべてを実行した結果、次のようなクラスが得られます。
public class StandardGestures implements OnTouchListener, OnGestureListener, OnDoubleTapListener, OnScaleGestureListener {
private View view;
private GestureDetector gesture;
private ScaleGestureDetector gestureScale;
private float scaleFactor = 1;
private boolean inScale;
public StandardGestures(Context c){
gesture = new GestureDetector(c, this);
gestureScale = new ScaleGestureDetector(c, this);
}
@Override
public boolean onTouch(View view, MotionEvent event) {
this.view = view;
gesture.onTouchEvent(event);
gestureScale.onTouchEvent(event);
return true;
}
@Override
public boolean onDown(MotionEvent event) {
return true;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float x, float y) {
return true;
}
@Override
public void onLongPress(MotionEvent event) {
}
@Override
public boolean onScroll(MotionEvent event1, MotionEvent event2, float x, float y) {
float newX = view.getX();
float newY = view.getY();
if(!inScale){
newX -= x;
newY -= y;
}
WindowManager wm = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
Point p = new Point();
d.getSize(p);
if (newX > (view.getWidth() * scaleFactor - p.x) / 2){
newX = (view.getWidth() * scaleFactor - p.x) / 2;
} else if (newX < -((view.getWidth() * scaleFactor - p.x) / 2)){
newX = -((view.getWidth() * scaleFactor - p.x) / 2);
}
if (newY > (view.getHeight() * scaleFactor - p.y) / 2){
newY = (view.getHeight() * scaleFactor - p.y) / 2;
} else if (newY < -((view.getHeight() * scaleFactor - p.y) / 2)){
newY = -((view.getHeight() * scaleFactor - p.y) / 2);
}
view.setX(newX);
view.setY(newY);
return true;
}
@Override
public void onShowPress(MotionEvent event) {
}
@Override
public boolean onSingleTapUp(MotionEvent event) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent event) {
view.setVisibility(View.GONE);
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent event) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = scaleFactor < 1 ? 1 : scaleFactor; // prevent our image from becoming too small
scaleFactor = (float) (int) (scaleFactor * 100) / 100; // Change precision to help with jitter when user just rests their fingers //
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
onScroll(null, null, 0, 0); // call scroll to make sure our bounds are still ok //
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
inScale = true;
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
inScale = false;
onScroll(null, null, 0, 0); // call scroll to make sure our bounds are still ok //
}
}
ScaleGestureDetector は、Android 2.2 (別名 Froyo、API レベル 8) 以降で利用できます。参照: http://android-developers.blogspot.com/2010/06/make-sense-of-multitouch.html
2.0/2.1 では、ScaleGestureDetector はありませんが、Pieter888 が上記にリンクした Ed Burnette による ZDNet ブログ エントリを使用して、ピンチ ツー ズームを提供できます: http://www.zdnet.com/blog/burnette/how -to-use-multi-touch-in-android-2-part-6-implementing-the-pinch-zoom-gesture/1847
実際には、このクラスを画像のズーム専用に使用するライブラリがあります。
「 TouchImageView」と呼ばれます
はい、ここにサンプル コードがあります。ここで、onPinch() と onZoom() は、独自に実装するアクションです。
public class simpleOnScaleGestureListener extends
SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
startScale = detector.getScaleFactor();
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
endScale = detector.getScaleFactor();
if (startScale > endScale) {
Log.i("onScaleEnd", "Pinch Dection");
onPinch();
} else if (startScale < endScale) {
Log.i("onScaleEnd", "Zoom Dection");
onZoom();
}
}
}