package com.mycom.lib.gesture.imageview;
import com.oxi.idivertido.R;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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;
import android.widget.ImageView;
/**
* This view supports both zooming and panning.
* What gets shown in the view depends on the onDraw method provided by subclasses.
* The default onDraw method defined here comes from R.drawable.zoom_view_sample.
*
* <p> Subclasses can change behavior by overriding methods sampleDrawableId,
* supportsZoom, supportsPan, supportsScaleAroundFocusPoint, drawOnCanvas.
*/
public class PanZoomView extends ImageView {
static protected final boolean ScaleAtFocusPoint = false;
static protected final int DefaultDrawableId = R.drawable.ic_launcher;
protected Drawable mSampleImage;
protected Context mContext;
protected float mPosX;
protected float mPosY;
protected float mPosX0 = 0; // initial displacement values
protected float mPosY0 = 0;;
protected float mFocusX; // these two focus variables are not needed
protected float mFocusY;
protected float mLastTouchX;
protected float mLastTouchY;
protected static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
protected int mActivePointerId = INVALID_POINTER_ID;
protected ScaleGestureDetector mScaleDetector;
protected float mScaleFactor = 1.f;
// The next three are set by calling supportsPan, supportsZoom, ...
protected boolean mSupportsPan = true;
protected boolean mSupportsZoom = true;
protected boolean mSupportsScaleAtFocus = true;
/**
*/
public PanZoomView (Context context) {
this(context, null, 0);
}
public PanZoomView (Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PanZoomView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
setupToDraw (context, attrs, defStyle);
setupScaleDetector (context, attrs, defStyle);
}
/**
* Calculate the inSampleSize to use in BitmapFactory.Options in order
* to load a drawable resource into a bitmap of the specified size.
*/
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
/**
* Decode a resource into a bitmap of the specified size.
*/
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
/**
* Do whatever drawing is appropriate for this view.
* The canvas object is already set up to be drawn on. That means that all translations and scaling
* operations have already been done.
*
* @param canvas Canvas
* @return void
*/
public void drawOnCanvas (Canvas canvas) {
mSampleImage.draw(canvas);
}
/**
* onDraw
*/
@Override public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
float x = 0, y = 0;
x = mPosX + mPosX0;
y = mPosY + mPosY0;
if (mSupportsZoom || mSupportsPan) {
if (mSupportsPan && !mSupportsZoom) {
canvas.translate(x, y);
canvas.scale(mScaleFactor, mScaleFactor);
Log.d ("Multitouch", "+p-z x, y : " + x + " " + y);
} else if (mSupportsPan && mSupportsZoom) {
if (mScaleDetector.isInProgress()) {
// Pinch zoom is in progress
// if (mSupportsPan) canvas.translate(mPosX, mPosY);
mFocusX = mScaleDetector.getFocusX ();
mFocusY = mScaleDetector.getFocusY ();
canvas.scale(mScaleFactor, mScaleFactor, mFocusX, mFocusY);
Log.d ("Multitouch", "+p+z x, y, focusX, focusY: " + x + " " + y + " " + mFocusX + " " + mFocusY);
} else {
// Pinch zoom is not in progress. Just do translation of canvas at whatever the current scale is.
canvas.translate(x, y);
canvas.scale(mScaleFactor, mScaleFactor);
Log.d ("Multitouch", "+p+z x, y : " + x + " " + y);
}
} else if (mSupportsZoom) {
// Not working perfectly when mPosX0 is set.
canvas.translate(mPosX0, mPosY0); // Translate canvas so center point can be chosen.
mFocusX = mScaleDetector.getFocusX ();
mFocusY = mScaleDetector.getFocusY ();
canvas.scale(mScaleFactor, mScaleFactor, mFocusX -mPosX0, mFocusY -mPosY0);
Log.d ("Multitouch", "-p+s x, y, focusX, focusY: " + mPosX0 + " " + mPosY0 + " " + mFocusX + " " + mFocusY);
}
}
// Do whatever drawing is appropriate for this class
drawOnCanvas (canvas);
canvas.restore();
}
/**
* Handle touch and multitouch events so panning and zooming can be supported.
*
*/
@Override public boolean onTouchEvent(MotionEvent ev) {
// If we are not supporting either zoom or pan, return early.
if (!mSupportsZoom && !mSupportsPan) return false;
// 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 view supports panning and
// ScaleGestureDetector isn't processing a gesture.
if (mSupportsPan && !mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
//mFocusX = mPosX;
//mFocusY = mPosY;
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;
}
/**
* Return the resource id of the sample image.
*
* @return int
*/
public int sampleDrawableId () {
return DefaultDrawableId;
}
/**
* This method sets up the scale detector object used by the view. It is called by the constructor.
*
* @return void
*/
protected void setupScaleDetector (Context context, AttributeSet attrs, int defStyle) {
// Create our ScaleGestureDetector
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
/**
* This method performs whatever set up is necessary to do drawing. It is called by the constructor.
* The default implementation checks to see if both panning and zooming are supported.
* And it also locates the sample drawable resource by calling sampleDrawableId.
* If that method returns 0, the sample image is not set up.
*
* @return void
*/
protected void setupToDraw (Context context, AttributeSet attrs, int defStyle) {
mSupportsPan = supportsPan ();
mSupportsZoom = supportsZoom ();
mSupportsScaleAtFocus = supportsScaleAtFocusPoint ();
int resourceId = sampleDrawableId ();
if (resourceId == 0) return;
mSampleImage = context.getResources().getDrawable (resourceId);
mSampleImage.setBounds(0, 0, mSampleImage.getIntrinsicWidth(), mSampleImage.getIntrinsicHeight());
}
/**
* superOnDraw - call the onDraw method of the superclass of PanZoomView.
* Use this if you want to replace the onDraw defined here in PanZoomView.
*/
@SuppressLint("WrongCall")
protected void superOnDraw(Canvas canvas) {
super.onDraw(canvas);
}
/**
* Return true if panning is supported.
*
* @return boolean
*/
public boolean supportsPan () {
return true;
}
/**
* Return true if scaling is done around the focus point of the pinch.
*
* @return boolean
*/
public boolean supportsScaleAtFocusPoint () {
return ScaleAtFocusPoint;
}
/**
* Return true if pinch zooming is supported.
*
* @return boolean
*/
public boolean supportsZoom () {
return true;
}
/**
*/
// Class definitions
/**
* ScaleListener
*
*/
protected class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (!mSupportsZoom) return true;
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
mFocusX = detector.getFocusX ();
mFocusY = detector.getFocusY ();
invalidate();
return true;
}
}
} // end class