Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Image View Pinch Zooming

I am using code sample from Making Sense of Multitouch for zooming image view. On ScaleListener I added ScaleGestureDetector.getFocusX() and getFocusY()for content to zoom about the focal point of the gesture. It is working fine.

The problem is, on first multitouch the entire Image drawing position is changing to the current touch point and zooming it from there. Could you help me to resolve this issue?

Here is My Code Sample For TouchImageView.

public class TouchImageViewSample extends ImageView {  private Paint borderPaint = null; private Paint backgroundPaint = null;  private float mPosX = 0f; private float mPosY = 0f;  private float mLastTouchX; private float mLastTouchY; private static final int INVALID_POINTER_ID = -1; private static final String LOG_TAG = "TouchImageView";  // The ‘active pointer’ is the one currently moving our object. private int mActivePointerId = INVALID_POINTER_ID;  public TouchImageViewSample(Context context) {     this(context, null, 0); }  public TouchImageViewSample(Context context, AttributeSet attrs) {     this(context, attrs, 0); }  private ScaleGestureDetector mScaleDetector; private float mScaleFactor = 1.f;  // Existing code ... public TouchImageViewSample(Context context, AttributeSet attrs, int defStyle) {     super(context, attrs, defStyle);     // Create our ScaleGestureDetector     mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());      borderPaint = new Paint();     borderPaint.setARGB(255, 255, 128, 0);     borderPaint.setStyle(Paint.Style.STROKE);     borderPaint.setStrokeWidth(4);      backgroundPaint = new Paint();     backgroundPaint.setARGB(32, 255, 255, 255);     backgroundPaint.setStyle(Paint.Style.FILL);  }  @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; }  /*  * (non-Javadoc)  *   * @see android.view.View#draw(android.graphics.Canvas)  */ @Override public void draw(Canvas canvas) {     super.draw(canvas);     canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, borderPaint); }  @Override public void onDraw(Canvas canvas) {     canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, backgroundPaint);     if (this.getDrawable() != null) {         canvas.save();         canvas.translate(mPosX, mPosY);          Matrix matrix = new Matrix();         matrix.postScale(mScaleFactor, mScaleFactor, pivotPointX,                 pivotPointY);         // canvas.setMatrix(matrix);          canvas.drawBitmap(                 ((BitmapDrawable) this.getDrawable()).getBitmap(), matrix,                 null);          // this.getDrawable().draw(canvas);         canvas.restore();     } }  /*  * (non-Javadoc)  *   * @see  * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable  * )  */ @Override public void setImageDrawable(Drawable drawable) {     // Constrain to given size but keep aspect ratio     int width = drawable.getIntrinsicWidth();     int height = drawable.getIntrinsicHeight();     mLastTouchX = mPosX = 0;     mLastTouchY = mPosY = 0;      int borderWidth = (int) borderPaint.getStrokeWidth();     mScaleFactor = Math.min(((float) getLayoutParams().width - borderWidth)             / width, ((float) getLayoutParams().height - borderWidth)             / height);     pivotPointX = (((float) getLayoutParams().width - borderWidth) - (int) (width * mScaleFactor)) / 2;     pivotPointY = (((float) getLayoutParams().height - borderWidth) - (int) (height * mScaleFactor)) / 2;     super.setImageDrawable(drawable); }  float pivotPointX = 0f; float pivotPointY = 0f;  private class ScaleListener extends         ScaleGestureDetector.SimpleOnScaleGestureListener {      @Override     public boolean onScale(ScaleGestureDetector detector) {         mScaleFactor *= detector.getScaleFactor();          pivotPointX = detector.getFocusX();         pivotPointY = detector.getFocusY();          Log.d(LOG_TAG, "mScaleFactor " + mScaleFactor);         Log.d(LOG_TAG, "pivotPointY " + pivotPointY + ", pivotPointX= "                 + pivotPointX);         mScaleFactor = Math.max(0.05f, mScaleFactor);          invalidate();         return true;     } } 

And here how I used it within my activity.

ImageView imageView = (ImageView) findViewById(R.id.imgView);  int hMargin = (int) (displayMetrics.widthPixels * .10); int vMargin = (int) (displayMetrics.heightPixels * .10);  RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(displayMetrics.widthPixels - (hMargin * 2), (int)(displayMetrics.heightPixels - btnCamera.getHeight()) - (vMargin * 2)); params.leftMargin = hMargin; params.topMargin =  vMargin; imageView.setLayoutParams(params); imageView.setImageDrawable(drawable); 
like image 452
MobDev Avatar asked May 17 '12 05:05

MobDev


People also ask

How do you pinch zoom on Android?

Tap anywhere on the screen, except the keyboard or navigation bar. Drag 2 fingers to move around the screen. Pinch with 2 fingers to adjust zoom. To stop magnification, use your magnification shortcut again.

How do you zoom in on a picture on android?

Press your thumb and a finger together on the screen and pull them apart. Think of this motion as the opposite of a pinch. This enlarges an area of the image. Repeat the reverse-pinch gesture to zoom in further.

Does pinch zoom change image?

Pinch-to-zoom on all devices may use algorithms, but only to scale the image — it doesn't change the content itself. This was an attempt to prevent the jury from getting a clearer view of the action, not a genuine challenge to the integrity of the video.

How do I use TouchImageView?

TouchImageViews placed in a ViewPager like the Gallery app. Mirror two TouchImageViews using onTouchImageViewListener and setZoom() . Click on TouchImageView to cycle through images. Note that the zoom state is maintained though the images are switched.


2 Answers

@Override public boolean onTouch(View v, MotionEvent event) {     // TODO Auto-generated method stub      ImageView view = (ImageView) v;     dumpEvent(event);      // Handle touch events here...     switch (event.getAction() & MotionEvent.ACTION_MASK) {     case MotionEvent.ACTION_DOWN:         savedMatrix.set(matrix);         start.set(event.getX(), event.getY());         Log.d(TAG, "mode=DRAG");         mode = DRAG;         break;     case MotionEvent.ACTION_POINTER_DOWN:         oldDist = spacing(event);         Log.d(TAG, "oldDist=" + oldDist);         if (oldDist > 10f) {             savedMatrix.set(matrix);             midPoint(mid, event);             mode = ZOOM;             Log.d(TAG, "mode=ZOOM");         }         break;     case MotionEvent.ACTION_UP:     case MotionEvent.ACTION_POINTER_UP:         mode = NONE;         Log.d(TAG, "mode=NONE");         break;     case MotionEvent.ACTION_MOVE:         if (mode == DRAG) {             // ...             matrix.set(savedMatrix);             matrix.postTranslate(event.getX() - start.x, event.getY()                     - start.y);         } else if (mode == ZOOM) {             float newDist = spacing(event);             Log.d(TAG, "newDist=" + newDist);             if (newDist > 10f) {                 matrix.set(savedMatrix);                 float scale = newDist / oldDist;                 matrix.postScale(scale, scale, mid.x, mid.y);             }         }         break;     }      view.setImageMatrix(matrix);     return true; }  private void dumpEvent(MotionEvent event) {     String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",             "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };     StringBuilder sb = new StringBuilder();     int action = event.getAction();     int actionCode = action & MotionEvent.ACTION_MASK;     sb.append("event ACTION_").append(names[actionCode]);     if (actionCode == MotionEvent.ACTION_POINTER_DOWN             || actionCode == MotionEvent.ACTION_POINTER_UP) {         sb.append("(pid ").append(                 action >> MotionEvent.ACTION_POINTER_ID_SHIFT);         sb.append(")");     }     sb.append("[");     for (int i = 0; i < event.getPointerCount(); i++) {         sb.append("#").append(i);         sb.append("(pid ").append(event.getPointerId(i));         sb.append(")=").append((int) event.getX(i));         sb.append(",").append((int) event.getY(i));         if (i + 1 < event.getPointerCount())             sb.append(";");     }     sb.append("]");     Log.d(TAG, sb.toString()); }  /** Determine the space between the first two fingers */ private float spacing(MotionEvent event) {     float x = event.getX(0) - event.getX(1);     float y = event.getY(0) - event.getY(1);     return FloatMath.sqrt(x * x + y * y); }  /** Calculate the mid point of the first two fingers */ private void midPoint(PointF point, MotionEvent event) {     float x = event.getX(0) + event.getX(1);     float y = event.getY(0) + event.getY(1);     point.set(x / 2, y / 2); } 

and dont forget to set scaleType property to matrix of ImageView tag like:

<ImageView     android:id="@+id/imageEnhance"     android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:layout_gravity="center_horizontal"     android:layout_marginBottom="15dp"     android:layout_marginLeft="15dp"     android:layout_marginRight="15dp"     android:layout_marginTop="15dp"     android:background="@drawable/enhanceimageframe"     android:scaleType="matrix" > </ImageView> 

and the variables used are:

// These matrices will be used to move and zoom image Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix();  // We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE;  // Remember some things for zooming PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; String savedItemClicked; 
like image 85
user Avatar answered Sep 19 '22 13:09

user


You can use this class : TouchImageView

like image 38
Anjula Avatar answered Sep 21 '22 13:09

Anjula