Created
December 15, 2012 15:38
-
-
Save naufraghi/4296434 to your computer and use it in GitHub Desktop.
Move and zoom image with Gestures in and android View
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.develer.circularsliderule; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.graphics.drawable.Drawable; | |
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 = getResources().getDrawable(R.drawable.ic_launcher); | |
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); | |
float pivotX, pivotY; | |
pivotX = mImage.getIntrinsicWidth()/2; | |
pivotY = mImage.getIntrinsicHeight()/2; | |
canvas.save(); | |
Log.d("DEBUG", "X: "+mPosX+" Y: "+mPosY); | |
Log.d("DEBUG", "pivotX: "+pivotX+" pivotY: "+pivotY); | |
canvas.translate(mPosX, mPosY); | |
canvas.scale(mScaleFactor, mScaleFactor, pivotX, pivotY); | |
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; | |
} | |
} | |
} |
hello
i was lots of research for zoom in and out, but this is nice.
but i have one problem, how can set limitation when i zoom in or out ?
thank in advance..
Hey @spDev002, i know it's been a while since you've asked, but you can limit the zoom in/out in this line
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
where 0.1 is the min and 10.0f is the max
hello
i was lots of research for zoom in and out, but this is nice.
but i have one problem, how can set limitation when i zoom in or out ?
thank in advance..
How to load image from URL?
Just because I spent some time on it, if anyone needs the image to always cover the whole canvas:
Put this at the end of onTouchEvent
int iWidth = mImage.getIntrinsicWidth();
int iHeight = mImage.getIntrinsicHeight();
// Clamp x pos
mPosX = Math.min(mPosX, -iWidth * (1 - mScaleFactor) / 2);
mPosX = Math.max(mPosX, -iWidth * (1 + mScaleFactor) / 2 + getWidth());
// Clamp y pos
mPosY = Math.min(mPosY, -iHeight * (1 - mScaleFactor) / 2);
mPosY = Math.max(mPosY, -iHeight * (1 + mScaleFactor) / 2 + getHeight());
And before invalidate()
in ScaleListener.onScale
// Clamp scale
float minXScale = (float) getWidth() / mImage.getIntrinsicWidth();
float minYScale = (float) getHeight() / mImage.getIntrinsicHeight();
mScaleFactor = Math.max(mScaleFactor, Math.max(minXScale, minYScale));
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nice usage of findPointerIndex().