Image AndroidVoir Zoom avant et Zoom arrière

Salut je suis nouveau à l’application Android que je veux Zoom-in et Zoom-Out ImageView.I a essayé la plupart de l’échantillon, mais dans toute cette image dans la vue de l’image est d’obtenir Zoom-in et Zoom-out.Je veux zoomer et Zoom-out ImageView.Je veux augmenter la largeur et la hauteur de la vue image tout en effectuant un zoom avant et en réduisant la largeur et la hauteur de la vue image lorsque vous effectuez un zoom arrière. Quelqu’un peut-il me suggérer?

Faire deux classes java

Classe de zoom

 import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.view.KeyEvent; import android.view.View; import android.widget.Button; import android.widget.ImageButton; public class Zoom extends View { private Drawable image; ImageButton img,img1; private int zoomControler=20; public Zoom(Context context){ super(context); image=context.getResources().getDrawable(R.drawable.j); //image=context.getResources().getDrawable(R.drawable.icon); setFocusable(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //here u can control the width and height of the images........ this line is very important image.setBounds((getWidth()/2)-zoomControler, (getHeight()/2)-zoomControler, (getWidth()/2)+zoomControler, (getHeight()/2)+zoomControler); image.draw(canvas); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode==KeyEvent.KEYCODE_DPAD_UP){ // zoom in zoomControler+=10; } if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){ // zoom out zoomControler-=10; } if(zoomControler<10){ zoomControler=10; } invalidate(); return true; } } 

faire deuxième classe

 import android.app.Activity; import android.os.Bundle; public class Zoomexample extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(new Zoom(this)); } } 

Veuillez suivre la classe ci-dessous, utilisée pour Zoom avant et Zoom arrière pour ImageView.

 import android.app.Activity; import android.graphics.Masortingx; import android.graphics.PointF; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; public class ZoomInZoomOut extends Activity implements OnTouchListener { private static final Ssortingng TAG = "Touch"; @SuppressWarnings("unused") private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f; // These masortingces will be used to scale points of the image Masortingx masortingx = new Masortingx(); Masortingx savedMasortingx = new Masortingx(); // The 3 states (events) which the user is trying to perform static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; // these PointF objects are used to record the point(s) the user is touching PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView view = (ImageView) findViewById(R.id.imageView); view.setOnTouchListener(this); } @Override public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; view.setScaleType(ImageView.ScaleType.MATRIX); float scale; dumpEvent(event); // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // first finger down only savedMasortingx.set(masortingx); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG"); // write to LogCat mode = DRAG; break; case MotionEvent.ACTION_UP: // first finger lifted case MotionEvent.ACTION_POINTER_UP: // second finger lifted mode = NONE; Log.d(TAG, "mode=NONE"); break; case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 5f) { savedMasortingx.set(masortingx); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { masortingx.set(savedMasortingx); masortingx.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the masortingx of points } else if (mode == ZOOM) { // pinch zooming float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 5f) { masortingx.set(savedMasortingx); scale = newDist / oldDist; // setting the scaling of the // masortingx...if scale > 1 means // zoom in...if scale < 1 means // zoom out matrix.postScale(scale, scale, mid.x, mid.y); } } break; } view.setImageMatrix(matrix); // display the transformation on screen return true; // indicate event was handled } /* * -------------------------------------------------------------------------- * Method: spacing Parameters: MotionEvent Returns: float Description: * checks the spacing between the two fingers on touch * ---------------------------------------------------- */ private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float) Math.sqrt(x * x + y * y); } /* * -------------------------------------------------------------------------- * Method: midPoint Parameters: PointF object, MotionEvent Returns: void * Description: calculates the midpoint between the 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); } /** Show an event in the LogCat view, for debugging */ 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("Touch Events ---------", sb.toString()); } } 

Les autres implémentations ici ont toutes une sorte de faille. donc je les ai essentiellement mélangés et est venu avec cela.

Créez une vue personnalisée comme celle-ci:

ZoomableImageView.java:

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.Masortingx; import android.graphics.PointF; import android.util.AtsortingbuteSet; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.widget.ImageView; public class ZoomableImageView extends ImageView { Masortingx masortingx = new Masortingx(); static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; static final int CLICK = 3; int mode = NONE; PointF last = new PointF(); PointF start = new PointF(); float minScale = 1f; float maxScale = 4f; float[] m; float redundantXSpace, redundantYSpace; float width, height; float saveScale = 1f; float right, bottom, origWidth, origHeight, bmWidth, bmHeight; ScaleGestureDetector mScaleDetector; Context context; public ZoomableImageView(Context context, AtsortingbuteSet attr) { super(context, attr); super.setClickable(true); this.context = context; mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); masortingx.setTranslate(1f, 1f); m = new float[9]; setImageMasortingx(masortingx); setScaleType(ScaleType.MATRIX); setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mScaleDetector.onTouchEvent(event); masortingx.getValues(m); float x = m[Masortingx.MTRANS_X]; float y = m[Masortingx.MTRANS_Y]; PointF curr = new PointF(event.getX(), event.getY()); switch (event.getAction()) { //when one finger is touching //set the mode to DRAG case MotionEvent.ACTION_DOWN: last.set(event.getX(), event.getY()); start.set(last); mode = DRAG; break; //when two fingers are touching //set the mode to ZOOM case MotionEvent.ACTION_POINTER_DOWN: last.set(event.getX(), event.getY()); start.set(last); mode = ZOOM; break; //when a finger moves //If mode is applicable move image case MotionEvent.ACTION_MOVE: //if the mode is ZOOM or //if the mode is DRAG and already zoomed if (mode == ZOOM || (mode == DRAG && saveScale > minScale)) { float deltaX = curr.x - last.x;// x difference float deltaY = curr.y - last.y;// y difference float scaleWidth = Math.round(origWidth * saveScale);// width after applying current scale float scaleHeight = Math.round(origHeight * saveScale);// height after applying current scale //if scaleWidth is smaller than the views width //in other words if the image width fits in the view //limit left and right movement if (scaleWidth < width) { deltaX = 0; if (y + deltaY > 0) deltaY = -y; else if (y + deltaY < -bottom) deltaY = -(y + bottom); } //if scaleHeight is smaller than the views height //in other words if the image height fits in the view //limit up and down movement else if (scaleHeight < height) { deltaY = 0; if (x + deltaX > 0) deltaX = -x; else if (x + deltaX < -right) deltaX = -(x + right); } //if the image doesnt fit in the width or height //limit both up and down and left and right else { if (x + deltaX > 0) deltaX = -x; else if (x + deltaX < -right) deltaX = -(x + right); if (y + deltaY > 0) deltaY = -y; else if (y + deltaY < -bottom) deltaY = -(y + bottom); } //move the image with the matrix matrix.postTranslate(deltaX, deltaY); //set the last touch location to the current last.set(curr.x, curr.y); } break; //first finger is lifted case MotionEvent.ACTION_UP: mode = NONE; int xDiff = (int) Math.abs(curr.x - start.x); int yDiff = (int) Math.abs(curr.y - start.y); if (xDiff < CLICK && yDiff < CLICK) performClick(); break; // second finger is lifted case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; } setImageMatrix(matrix); invalidate(); return true; } }); } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); bmWidth = bm.getWidth(); bmHeight = bm.getHeight(); } public void setMaxZoom(float x) { maxScale = x; } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mode = ZOOM; return true; } @Override public boolean onScale(ScaleGestureDetector detector) { float mScaleFactor = detector.getScaleFactor(); float origScale = saveScale; saveScale *= mScaleFactor; if (saveScale > maxScale) { saveScale = maxScale; mScaleFactor = maxScale / origScale; } else if (saveScale < minScale) { saveScale = minScale; mScaleFactor = minScale / origScale; } right = width * saveScale - width - (2 * redundantXSpace * saveScale); bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); if (origWidth * saveScale <= width || origHeight * saveScale <= height) { matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2); if (mScaleFactor < 1) { matrix.getValues(m); float x = m[Matrix.MTRANS_X]; float y = m[Matrix.MTRANS_Y]; if (mScaleFactor < 1) { if (Math.round(origWidth * saveScale) < width) { if (y < -bottom) matrix.postTranslate(0, -(y + bottom)); else if (y > 0) masortingx.postTranslate(0, -y); } else { if (x < -right) matrix.postTranslate(-(x + right), 0); else if (x > 0) masortingx.postTranslate(-x, 0); } } } } else { masortingx.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY()); masortingx.getValues(m); float x = m[Masortingx.MTRANS_X]; float y = m[Masortingx.MTRANS_Y]; if (mScaleFactor < 1) { if (x < -right) matrix.postTranslate(-(x + right), 0); else if (x > 0) masortingx.postTranslate(-x, 0); if (y < -bottom) matrix.postTranslate(0, -(y + bottom)); else if (y > 0) masortingx.postTranslate(0, -y); } } return true; } } @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec); //Fit to screen. float scale; float scaleX = width / bmWidth; float scaleY = height / bmHeight; scale = Math.min(scaleX, scaleY); masortingx.setScale(scale, scale); setImageMasortingx(masortingx); saveScale = 1f; // Center the image redundantYSpace = height - (scale * bmHeight) ; redundantXSpace = width - (scale * bmWidth); redundantYSpace /= 2; redundantXSpace /= 2; masortingx.postTranslate(redundantXSpace, redundantYSpace); origWidth = width - 2 * redundantXSpace; origHeight = height - 2 * redundantYSpace; right = width * saveScale - width - (2 * redundantXSpace * saveScale); bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); setImageMasortingx(masortingx); } } 

Ensuite, ajoutez l’image comme ceci:

 ZoomableImageView touch = (ZoomableImageView)findViewById(R.id.IMAGEID); touch.setImageBitmap(bitmap); 

Ajoutez la vue comme ceci dans XML:

  

Manière simple:

 PhotoViewAttacher pAttacher; pAttacher = new PhotoViewAttacher(Your_Image_View); pAttacher.update(); 

Ajouter la ligne ci-dessous dans build.gradle :

 comstack 'com.commit451:PhotoView:1.2.4' 

il suffit d’utiliser cette classe: TouchImageView

C’est encore une autre implémentation basée sur le code posté par Nicolas Tyler.

Les bogues suivants sont corrigés:

  • Le réglage de minScale sur un nombre inférieur à 1 fonctionne maintenant
  • Vous n’avez pas besoin d’utiliser setImageBitmap() pour définir l’image (vous pouvez utiliser, par exemple, setImageResource()
  • Tous les constructeurs fonctionnent maintenant correctement

Les choses suivantes, entre autres, sont rangées:

  • Un OnTouchListener n’est pas utilisé, ce n’est pas nécessaire car la classe peut simplement implémenter la méthode onTouchEvent() .

  • L’assignation right = width * saveScale - width - (2 * redundantXSpace * saveScale); a été simplifié à right = (originalBitmapWidth * saveScale) - width Ce qui, dans mon option, est beaucoup moins déroutant.

  • Certaines variables membres sont supprimées (d’autres états peuvent probablement être supprimés de cette classe)

Ce n’est pas parfait mais vous voilà:

 import android.content.Context; import android.graphics.Masortingx; import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.util.AtsortingbuteSet; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.widget.ImageView; /** * Created by alex on 23/02/16. * Based on code posted by Nicolas Tyler here: * https://stackoverflow.com/questions/6650398/android-imageview-zoom-in-and-zoom-out */ public class ZoomableImageView extends ImageView { private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mode = ZOOM; return true; } @Override public boolean onScale(ScaleGestureDetector detector) { float scaleFactor = detector.getScaleFactor(); float newScale = saveScale * scaleFactor; if (newScale < maxScale && newScale > minScale) { saveScale = newScale; float width = getWidth(); float height = getHeight(); right = (originalBitmapWidth * saveScale) - width; bottom = (originalBitmapHeight * saveScale) - height; float scaledBitmapWidth = originalBitmapWidth * saveScale; float scaledBitmapHeight = originalBitmapHeight * saveScale; if (scaledBitmapWidth < = width || scaledBitmapHeight <= height) { matrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2); } else { matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); } } return true; } } static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; static final int CLICK = 3; private int mode = NONE; private Matrix matrix = new Matrix(); private PointF last = new PointF(); private PointF start = new PointF(); private float minScale = 0.5f; private float maxScale = 4f; private float[] m; private float redundantXSpace, redundantYSpace; private float saveScale = 1f; private float right, bottom, originalBitmapWidth, originalBitmapHeight; private ScaleGestureDetector mScaleDetector; public ZoomableImageView(Context context) { super(context); init(context); } public ZoomableImageView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ZoomableImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { super.setClickable(true); mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); m = new float[9]; setImageMatrix(matrix); setScaleType(ScaleType.MATRIX); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int bmHeight = getBmHeight(); int bmWidth = getBmWidth(); float width = getMeasuredWidth(); float height = getMeasuredHeight(); //Fit to screen. float scale = width > height ? height / bmHeight : width / bmWidth; masortingx.setScale(scale, scale); saveScale = 1f; originalBitmapWidth = scale * bmWidth; originalBitmapHeight = scale * bmHeight; // Center the image redundantYSpace = (height - originalBitmapHeight); redundantXSpace = (width - originalBitmapWidth); masortingx.postTranslate(redundantXSpace / 2, redundantYSpace / 2); setImageMasortingx(masortingx); } @Override public boolean onTouchEvent(MotionEvent event) { mScaleDetector.onTouchEvent(event); masortingx.getValues(m); float x = m[Masortingx.MTRANS_X]; float y = m[Masortingx.MTRANS_Y]; PointF curr = new PointF(event.getX(), event.getY()); switch (event.getAction()) { //when one finger is touching //set the mode to DRAG case MotionEvent.ACTION_DOWN: last.set(event.getX(), event.getY()); start.set(last); mode = DRAG; break; //when two fingers are touching //set the mode to ZOOM case MotionEvent.ACTION_POINTER_DOWN: last.set(event.getX(), event.getY()); start.set(last); mode = ZOOM; break; //when a finger moves //If mode is applicable move image case MotionEvent.ACTION_MOVE: //if the mode is ZOOM or //if the mode is DRAG and already zoomed if (mode == ZOOM || (mode == DRAG && saveScale > minScale)) { float deltaX = curr.x - last.x;// x difference float deltaY = curr.y - last.y;// y difference float scaleWidth = Math.round(originalBitmapWidth * saveScale);// width after applying current scale float scaleHeight = Math.round(originalBitmapHeight * saveScale);// height after applying current scale boolean limitX = false; boolean limitY = false; //if scaleWidth is smaller than the views width //in other words if the image width fits in the view //limit left and right movement if (scaleWidth < getWidth() && scaleHeight < getHeight()) { // don't do anything } else if (scaleWidth < getWidth()) { deltaX = 0; limitY = true; } //if scaleHeight is smaller than the views height //in other words if the image height fits in the view //limit up and down movement else if (scaleHeight < getHeight()) { deltaY = 0; limitX = true; } //if the image doesnt fit in the width or height //limit both up and down and left and right else { limitX = true; limitY = true; } if (limitY) { if (y + deltaY > 0) { deltaY = -y; } else if (y + deltaY < -bottom) { deltaY = -(y + bottom); } } if (limitX) { if (x + deltaX > 0) { deltaX = -x; } else if (x + deltaX < -right) { deltaX = -(x + right); } } //move the image with the matrix matrix.postTranslate(deltaX, deltaY); //set the last touch location to the current last.set(curr.x, curr.y); } break; //first finger is lifted case MotionEvent.ACTION_UP: mode = NONE; int xDiff = (int) Math.abs(curr.x - start.x); int yDiff = (int) Math.abs(curr.y - start.y); if (xDiff < CLICK && yDiff < CLICK) performClick(); break; // second finger is lifted case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; } setImageMatrix(matrix); invalidate(); return true; } public void setMaxZoom(float x) { maxScale = x; } private int getBmWidth() { Drawable drawable = getDrawable(); if (drawable != null) { return drawable.getIntrinsicWidth(); } return 0; } private int getBmHeight() { Drawable drawable = getDrawable(); if (drawable != null) { return drawable.getIntrinsicHeight(); } return 0; } } 

J’ai fait ma propre imageview avec pincement pour zoomer. Il n’y a pas de limites / frontières sur le code de Chirag Raval , l’utilisateur peut donc faire glisser l’image hors de l’écran.

Voici la classe CustomImageView:

  public class CustomImageVIew extends ImageView implements OnTouchListener { private Masortingx masortingx = new Masortingx(); private Masortingx savedMasortingx = new Masortingx(); static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; private int mode = NONE; private PointF mStartPoint = new PointF(); private PointF mMiddlePoint = new PointF(); private Point mBitmapMiddlePoint = new Point(); private float oldDist = 1f; private float masortingxValues[] = {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f}; private float scale; private float oldEventX = 0; private float oldEventY = 0; private float oldStartPointX = 0; private float oldStartPointY = 0; private int mViewWidth = -1; private int mViewHeight = -1; private int mBitmapWidth = -1; private int mBitmapHeight = -1; private boolean mDraggable = false; public CustomImageVIew(Context context) { this(context, null, 0); } public CustomImageVIew(Context context, AtsortingbuteSet attrs) { this(context, attrs, 0); } public CustomImageVIew(Context context, AtsortingbuteSet attrs, int defStyle) { super(context, attrs, defStyle); this.setOnTouchListener(this); } @Override public void onSizeChanged (int w, int h, int oldw, int oldh){ super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; mViewHeight = h; } public void setBitmap(Bitmap bitmap){ if(bitmap != null){ setImageBitmap(bitmap); mBitmapWidth = bitmap.getWidth(); mBitmapHeight = bitmap.getHeight(); mBitmapMiddlePoint.x = (mViewWidth / 2) - (mBitmapWidth / 2); mBitmapMiddlePoint.y = (mViewHeight / 2) - (mBitmapHeight / 2); masortingx.postTranslate(mBitmapMiddlePoint.x, mBitmapMiddlePoint.y); this.setImageMasortingx(masortingx); } } @Override public boolean onTouch(View v, MotionEvent event){ switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMasortingx.set(masortingx); mStartPoint.set(event.getX(), event.getY()); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); if(oldDist > 10f){ savedMasortingx.set(masortingx); midPoint(mMiddlePoint, event); mode = ZOOM; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; case MotionEvent.ACTION_MOVE: if(mode == DRAG){ drag(event); } else if(mode == ZOOM){ zoom(event); } break; } return true; } public void drag(MotionEvent event){ masortingx.getValues(masortingxValues); float left = masortingxValues[2]; float top = masortingxValues[5]; float bottom = (top + (masortingxValues[0] * mBitmapHeight)) - mViewHeight; float right = (left + (masortingxValues[0] * mBitmapWidth)) -mViewWidth; float eventX = event.getX(); float eventY = event.getY(); float spacingX = eventX - mStartPoint.x; float spacingY = eventY - mStartPoint.y; float newPositionLeft = (left < 0 ? spacingX : spacingX * -1) + left; float newPositionRight = (spacingX) + right; float newPositionTop = (top < 0 ? spacingY : spacingY * -1) + top; float newPositionBottom = (spacingY) + bottom; boolean x = true; boolean y = true; if(newPositionRight < 0.0f || newPositionLeft > 0.0f){ if(newPositionRight < 0.0f && newPositionLeft > 0.0f){ x = false; } else{ eventX = oldEventX; mStartPoint.x = oldStartPointX; } } if(newPositionBottom < 0.0f || newPositionTop > 0.0f){ if(newPositionBottom < 0.0f && newPositionTop > 0.0f){ y = false; } else{ eventY = oldEventY; mStartPoint.y = oldStartPointY; } } if(mDraggable){ masortingx.set(savedMasortingx); masortingx.postTranslate(x? eventX - mStartPoint.x : 0, y? eventY - mStartPoint.y : 0); this.setImageMasortingx(masortingx); if(x)oldEventX = eventX; if(y)oldEventY = eventY; if(x)oldStartPointX = mStartPoint.x; if(y)oldStartPointY = mStartPoint.y; } } public void zoom(MotionEvent event){ masortingx.getValues(masortingxValues); float newDist = spacing(event); float bitmapWidth = masortingxValues[0] * mBitmapWidth; float bimtapHeight = masortingxValues[0] * mBitmapHeight; boolean in = newDist > oldDist; if(!in && masortingxValues[0] < 1){ return; } if(bitmapWidth > mViewWidth || bimtapHeight > mViewHeight){ mDraggable = true; } else{ mDraggable = false; } float midX = (mViewWidth / 2); float midY = (mViewHeight / 2); masortingx.set(savedMasortingx); scale = newDist / oldDist; masortingx.postScale(scale, scale, bitmapWidth > mViewWidth ? mMiddlePoint.x : midX, bimtapHeight > mViewHeight ? mMiddlePoint.y : midY); this.setImageMasortingx(masortingx); } /** 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 (float)Math.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); } } 

Voici comment vous pouvez l’utiliser dans votre activité:

 CustomImageVIew mImageView = (CustomImageVIew)findViewById(R.id.customImageVIew1); mImage.setBitmap(your bitmap); 

Et mise en page:

  // important 

J’ai eu la réponse la plus utile de @Nicolas Tyler mais j’ai eu des problèmes avec le fonctionnement de la syntaxe et de la logique. Je ne voulais pas non plus d’espace Alpha et mon algèbre était rouillée! Au bout de 3 jours, j’ai mis au point ma propre version.

Ma réponse diffère de @Nicolas Tyler avec ce qui suit:

  1. Les différents noms de variables que j’ai trouvés ont plus de sens dans les utilisations contextuelles sous-jacentes

  2. Cette classe d’image Pinch-Zoom n’affiche PAS d’espace alpha et vous permet de zoomer et dézoomer et de ne pas vous déplacer sur / sous une image et de révéler un espace alpha

  3. Ajout de commentaires profonds à la section masortingce pour expliquer ce qui se passait avec les mathématiques impliquées

  4. Cette classe d’image vous laissera également passer un resourceId et créera une image bitmap

  5. Des algorithmes beaucoup plus simples pour la mise à l’échelle et la traduction et peu de variables

  6. Changer l’image à l’intérieur entraînera un zoom avant / arrière tel que la nouvelle image occupe le conteneur de vue

Vous trouverez ici un aperçu complet des ressources sur Algèbre: https://youtu.be/IiXB6tYtY4w?t=4m12s Cette vidéo couvre le cœur des masortingces Scalar et Translation (et vous aidera à comprendre les fonctionnalités MTRANS_X et MTRANS_Y). Si vous avez des questions, demandez et je ferai de mon mieux pour répondre (mais je ne suis PAS un expert en algèbre).

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Masortingx; import android.graphics.PointF; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.widget.ImageView; public class iImage extends ImageView { static final int NONE_MODE = 0; static final int DRAG_MODE = 1; static final int ZOOM_MODE = 2; int _mode = NONE_MODE; Masortingx _masortingx = new Masortingx(); PointF _previousPoint = new PointF(); PointF _startPoint = new PointF(); float _currentScale = 1f; float _minScale = 1f; float _maxScale = 3f; float[] _arrayOf9Floats; float _bitmapWidth, _bitmapHeight,_displayWidth, _displayHeight; ScaleGestureDetector _scaleDetector; Context _context; public iImage(Context context) { super(context); super.setClickable(true); _context = context; _scaleDetector = new ScaleGestureDetector(context, new ScaleListener()); _arrayOf9Floats = new float[9]; setScaleType(ScaleType.MATRIX); setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return handleTouch(v, event); } }); } private boolean handleTouch(View v, MotionEvent event) { _scaleDetector.onTouchEvent(event); //Contrary to how this line looks, the masortingx is not setting the values from the arrayOf9Floats, but rather taking the //masortingx values and assigning them into the arrayOf9Floats. I extremely dislike this syntax and I think //it should have been written as _arrayOf9Floats = _masortingx.getValues() but that's Android for you!!! _masortingx.getValues(_arrayOf9Floats); //Look at https://youtu.be/IiXB6tYtY4w?t=4m12s , it shows scale, rotate, and translate masortingces //If you look at the translate masortingx, you'll see that the 3rd and 6th values are the values which represent x and y translations respectively //this corresponds to the 2nd and 5th values in the array and hence why the MTRANS_X and MTRANS_Y have the constants 2 and 5 respectively float xTranslate = _arrayOf9Floats[Masortingx.MTRANS_X]; float yTranslate = _arrayOf9Floats[Masortingx.MTRANS_Y]; PointF currentEventPoint = new PointF(event.getX(), event.getY()); switch (event.getAction()) { //First finger down only case MotionEvent.ACTION_DOWN: _previousPoint.set(event.getX(), event.getY()); _startPoint.set(_previousPoint); _mode = DRAG_MODE; break; //Second finger down case MotionEvent.ACTION_POINTER_DOWN: _previousPoint.set(event.getX(), event.getY()); _startPoint.set(_previousPoint); _mode = ZOOM_MODE; break; case MotionEvent.ACTION_MOVE: if (_mode == ZOOM_MODE || _mode == DRAG_MODE ) { float deltaX = currentEventPoint.x - _previousPoint.x; float deltaY = currentEventPoint.y - _previousPoint.y; //In masortingx terms, going right is + and going left is + //Moving the image right past 0 means it will show alpha space on the left so we dont want that //Keep in mind this is a TOP LEFT pivot point, so we dont want the top left to be past 0 lest we have alpha space if(xTranslate + deltaX > 0) { //get absolute of how much into the negative we would have gone float excessDeltaX = Math.abs(xTranslate + deltaX); //take that excess away from deltaX so X wont got less than 0 after the translation deltaX = deltaX - excessDeltaX; } //Going left we dont want the negative value to be less than the negative width of the sprite, lest we get alpha space on the right //The width is going to be the width of the bitmap * scale and we want the - of it because we are checking for left movement //We also need to account for the width of the DISPLAY CONTAINER (ie _displayWidth) so that gets subtracted //ie we want the max scroll width value float maxScrollableWidth = _bitmapWidth * _currentScale - _displayWidth; if(xTranslate + deltaX < -maxScrollableWidth) { //this forces the max possible translate to always match the - of maxScrollableWidth deltaX = -maxScrollableWidth - xTranslate; } //repeat for Y if(yTranslate + deltaY > 0) { float excessDeltaY = Math.abs(yTranslate + deltaY); deltaY = deltaY - excessDeltaY; } float maxScrollableHeight = _bitmapHeight * _currentScale - _displayWidth; if(yTranslate + deltaY < -maxScrollableHeight) { //this forces the max possible translate to always match the - of maxScrollableWidth deltaY = -maxScrollableHeight - yTranslate; } _matrix.postTranslate(deltaX, deltaY); _matrix.getValues(_arrayOf9Floats); //System.out.println(_matrix); _previousPoint.set(currentEventPoint.x, currentEventPoint.y); } break; case MotionEvent.ACTION_POINTER_UP: _mode = NONE_MODE; break; } setImageMatrix(_matrix); invalidate(); return true; } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); _bitmapWidth = bm.getWidth(); _bitmapHeight = bm.getHeight(); invalidate(); } @Override public void setImageResource(int resid) { Bitmap bitmapImage = BitmapFactory.decodeResource(_context.getResources(), resid); setImageBitmap(bitmapImage); } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { _mode = ZOOM_MODE; return true; } @Override public boolean onScale(ScaleGestureDetector detector) { float scaleFactor = detector.getScaleFactor(); float originalScale = _currentScale; _currentScale *= scaleFactor; //Zoom in too much if (_currentScale > _maxScale) { _currentScale = _maxScale; scaleFactor = _maxScale / originalScale; }//Zoom out too much else if (_currentScale < _minScale) { _currentScale = _minScale; scaleFactor = _minScale / originalScale; } _matrix.postScale(scaleFactor,scaleFactor); return true; } } @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); _displayWidth = MeasureSpec.getSize(widthMeasureSpec); _displayHeight = MeasureSpec.getSize(heightMeasureSpec); adjustScale(); } private void adjustScale() { //Fit to display bounds with NO alpha space float scale; float scaleX = _displayWidth / _bitmapWidth; float scaleY = _displayHeight / _bitmapHeight; scale = Math.max(scaleX, scaleY); _matrix.setScale(scale, scale); setImageMatrix(_matrix); _currentScale = scale; _minScale = scale; } public void setMaxZoom(float maxZoom){_maxScale = maxZoom;} public void setMinZoom(float minZoom) {_minScale = minZoom;} } 

Ce code fonctionne et implémente le double tap pour revenir à la taille de l’image d’origine.

1ère étape – Dans votre mise en page XML, mettez ceci:

  

2ème étape – Créer un fichier (TouchImageView.java) avec la classe TouchImageView:

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Masortingx; import android.graphics.PointF; import android.util.AtsortingbuteSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.widget.ImageView; public class TouchImageView extends ImageView { Masortingx masortingx; // 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 last = new PointF(); PointF start = new PointF(); float minScale = 1f; float maxScale = 3f; float[] m; float redundantXSpace, redundantYSpace, origRedundantXSpace, origRedundantYSpace; int viewWidth, viewHeight; static final int CLICK = 3; static final float SAVE_SCALE = 1f; float saveScale = SAVE_SCALE; protected float origWidth, origHeight; int oldMeasuredWidth, oldMeasuredHeight; float origScale, bottom, origBottom, right, origRight; ScaleGestureDetector mScaleDetector; GestureDetector mGestureDetector; Context context; public TouchImageView(Context context) { super(context); sharedConstructing(context); } public TouchImageView(Context context, AtsortingbuteSet attrs) { super(context, attrs); sharedConstructing(context); } private void sharedConstructing(Context context) { super.setClickable(true); this.context = context; mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); masortingx = new Masortingx(); m = new float[9]; setImageMasortingx(masortingx); setScaleType(ScaleType.MATRIX); setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { boolean onDoubleTapEvent = mGestureDetector.onTouchEvent(event); if (onDoubleTapEvent) { // Reset Image to original scale values mode = NONE; bottom = origBottom; right = origRight; last = new PointF(); start = new PointF(); m = new float[9]; saveScale = SAVE_SCALE; masortingx = new Masortingx(); masortingx.setScale(origScale, origScale); masortingx.postTranslate(origRedundantXSpace, origRedundantYSpace); setImageMasortingx(masortingx); invalidate(); return true; } mScaleDetector.onTouchEvent(event); PointF curr = new PointF(event.getX(), event.getY()); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: last.set(curr); start.set(last); mode = DRAG; break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { float deltaX = curr.x - last.x; float deltaY = curr.y - last.y; float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale); float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale); masortingx.postTranslate(fixTransX, fixTransY); fixTrans(); last.set(curr.x, curr.y); } break; case MotionEvent.ACTION_UP: mode = NONE; int xDiff = (int) Math.abs(curr.x - start.x); int yDiff = (int) Math.abs(curr.y - start.y); if (xDiff < CLICK && yDiff < CLICK) performClick(); break; case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; } setImageMatrix(matrix); invalidate(); return true; // indicate event was handled } }); mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTapEvent(MotionEvent e) { return true; } }); } public void setMaxZoom(float x) { maxScale = x; } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mode = ZOOM; return true; } @Override public boolean onScale(ScaleGestureDetector detector) { float mScaleFactor = detector.getScaleFactor(); //float mScaleFactor = (float) Math.min(Math.max(.95f, detector.getScaleFactor()), 1.05); float origScale = saveScale; saveScale *= mScaleFactor; if (saveScale > maxScale) { saveScale = maxScale; mScaleFactor = maxScale / origScale; } else if (saveScale < minScale) { saveScale = minScale; mScaleFactor = minScale / origScale; } right = viewWidth * saveScale - viewWidth - (2 * redundantXSpace * saveScale); bottom = viewHeight * saveScale - viewHeight - (2 * redundantYSpace * saveScale); if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight) matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2); else matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY()); fixTrans(); return true; } } void fixTrans() { matrix.getValues(m); float transX = m[Matrix.MTRANS_X]; float transY = m[Matrix.MTRANS_Y]; float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale); float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale); if (fixTransX != 0 || fixTransY != 0) matrix.postTranslate(fixTransX, fixTransY); } float getFixTrans(float trans, float viewSize, float contentSize) { float minTrans, maxTrans; if (contentSize <= viewSize) { minTrans = 0; maxTrans = viewSize - contentSize; } else { minTrans = viewSize - contentSize; maxTrans = 0; } if (trans < minTrans) return -trans + minTrans; if (trans > maxTrans) return -trans + maxTrans; return 0; } float getFixDragTrans(float delta, float viewSize, float contentSize) { if (contentSize < = viewSize) { return 0; } return delta; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); viewWidth = MeasureSpec.getSize(widthMeasureSpec); viewHeight = MeasureSpec.getSize(heightMeasureSpec); // // Rescales image on rotation // if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return; oldMeasuredHeight = viewHeight; oldMeasuredWidth = viewWidth; if (saveScale == 1) { // Fit to screen. float scale; int bmWidth,bmHeight; Bitmap bm = BitmapFactory.decodeResource(context.getResources(), R.mipmap.myinfolinks_splash); bmWidth = bm.getWidth(); bmHeight = bm.getHeight(); int w = bmWidth; int h = bmHeight; viewWidth = resolveSize(w, widthMeasureSpec); viewHeight = resolveSize(h, heightMeasureSpec); float scaleX = (float) viewWidth / (float) bmWidth; float scaleY = (float) viewHeight / (float) bmHeight; scale = Math.min(scaleX, scaleY); matrix.setScale(scale, scale); saveScale = SAVE_SCALE; origScale = scale; // Center the image redundantYSpace = (float) viewHeight - (scale * (float) bmHeight); redundantXSpace = (float) viewWidth - (scale * (float) bmWidth); redundantYSpace /= (float) 2; redundantXSpace /= (float) 2; origRedundantXSpace = redundantXSpace; origRedundantYSpace = redundantYSpace; matrix.postTranslate(redundantXSpace, redundantYSpace); origWidth = viewWidth - 2 * redundantXSpace; origHeight = viewHeight - 2 * redundantYSpace; right = viewWidth * saveScale - viewWidth - (2 * redundantXSpace * saveScale); bottom = viewHeight * saveScale - viewHeight - (2 * redundantYSpace * saveScale); origRight = right; origBottom = bottom; setImageMatrix(matrix); } fixTrans(); } } 

Et enfin, appelez dans votre activité principale:

 TouchImageView imgDisplay = (TouchImageView) messageView.findViewById(R.id.id_myImage); imgDisplay.setMaxZoom(2f); imgDisplay.setImageResource(R.drawable.myImage); 

J'ai vu beaucoup de code et après mes ajustements ça marche. Prendre plaisir!

I think Chirag Ravals’ answer is great!

The only thing it could be improved is moving all this code inside some class like:

 PinchZoomImageView extends ImageView {... 

and adding there initial Image Masortingx initialization to prevent zooming after the first tap:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); masortingx = new Masortingx(this.getImageMasortingx()); } 

BTW, this will fix a bug mentioned by Muhammad Umar and Baz

PS Having Max and Min zoom limits could be also useful. Eg Max zoom is 2X and min zoom is the original scale when the image is fitted to screen:

 static final int MAX_SCALE_FACTOR = 2; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Getting initial Image masortingx mViewMasortingx = new Masortingx(this.getImageMasortingx()); mMinScaleMasortingx = new Masortingx(mViewMasortingx); float initialScale = getMasortingxScale(mViewMasortingx); if (initialScale < 1.0f) // Image is bigger than screen mMaxScale = MAX_SCALE_FACTOR; else mMaxScale = MAX_SCALE_FACTOR * initialScale; mMinScale = getMatrixScale(mMinScaleMatrix); } @Override public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; // We set scale only after onMeasure was called and automatically fit image to screen if(!mWasScaleTypeSet) { view.setScaleType(ImageView.ScaleType.MATRIX); mWasScaleTypeSet = true; } float scale; dumpEvent(event); switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // first finger down only mCurSavedMatrix.set(mViewMatrix); start.set(event.getX(), event.getY()); mCurrentMode = DRAG; break; case MotionEvent.ACTION_UP: // first finger lifted case MotionEvent.ACTION_POINTER_UP: // second finger lifted mCurrentMode = NONE; float resScale = getMatrixScale(mViewMatrix); if (resScale > mMaxScale) { downscaleMasortingx(resScale, mViewMasortingx); } else if (resScale < mMinScale) mViewMatrix = new Matrix(mMinScaleMatrix); else if ((resScale - mMinScale) < 0.1f) // Don't allow user to drag picture outside in case of FIT TO WINDOW zoom mViewMatrix = new Matrix(mMinScaleMatrix); else break; break; case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down mOldDist = spacing(event); Helper.LOGD(TAG, "oldDist=" + mOldDist); if (mOldDist > 5f) { mCurSavedMasortingx.set(mViewMasortingx); midPoint(mCurMidPoint, event); mCurrentMode = ZOOM; Helper.LOGD(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_MOVE: if (mCurrentMode == DRAG) { mViewMasortingx.set(mCurSavedMasortingx); mViewMasortingx.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the masortingx of points } else if (mCurrentMode == ZOOM) { // pinch zooming float newDist = spacing(event); Helper.LOGD(TAG, "newDist=" + newDist); if (newDist > 1.f) { mViewMasortingx.set(mCurSavedMasortingx); scale = newDist / mOldDist; // setting the scaling of the // masortingx...if scale > 1 means // zoom in...if scale < 1 means // zoom out mViewMatrix.postScale(scale, scale, mCurMidPoint.x, mCurMidPoint.y); } } break; } view.setImageMatrix(mViewMatrix); // display the transformation on screen return true; // indicate event was handled } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////// PRIVATE SECTION /////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // These matrices will be used to scale points of the image private Matrix mViewMatrix = new Matrix(); private Matrix mCurSavedMatrix = new Matrix(); // These PointF objects are used to record the point(s) the user is touching private PointF start = new PointF(); private PointF mCurMidPoint = new PointF(); private float mOldDist = 1f; private Matrix mMinScaleMatrix; private float mMinScale; private float mMaxScale; float[] mTmpValues = new float[9]; private boolean mWasScaleTypeSet; /** * Returns scale factor of the Matrix * @param matrix * @return */ private float getMatrixScale(Matrix matrix) { matrix.getValues(mTmpValues); return mTmpValues[Matrix.MSCALE_X]; } /** * Downscales matrix with the scale to maximum allowed scale factor, but the same translations * @param scale * @param dist */ private void downscaleMatrix(float scale, Matrix dist) { float resScale = mMaxScale / scale; dist.postScale(resScale, resScale, mCurMidPoint.x, mCurMidPoint.y); } 

I have improved the answer I got from stack for flawless ZOOM (two finger) / ROTATION (two finger) / DRAG (Single finger) .

entrer la description de l'image ici

//============================XML code==================

 < ?xml version="1.0" encoding="utf-8"?>    

//============================Java code==========================

 public class MainActivity extends AppCompatActivity { ImageView photoview2; float[] lastEvent = null; float d = 0f; float newRot = 0f; private boolean isZoomAndRotate; private boolean isOutSide; private static final int NONE = 0; private static final int DRAG = 1; private static final int ZOOM = 2; private int mode = NONE; private PointF start = new PointF(); private PointF mid = new PointF(); float oldDist = 1f; private float xCoOrdinate, yCoOrdinate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_main); photoview2 = findViewById(R.id.imageview_trash); photoview2.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; view.bringToFront(); viewTransformation(view, event); return true; } }); } private void viewTransformation(View view, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: xCoOrdinate = view.getX() - event.getRawX(); yCoOrdinate = view.getY() - event.getRawY(); start.set(event.getX(), event.getY()); isOutSide = false; mode = DRAG; lastEvent = null; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); if (oldDist > 10f) { midPoint(mid, event); mode = ZOOM; } lastEvent = new float[4]; lastEvent[0] = event.getX(0); lastEvent[1] = event.getX(1); lastEvent[2] = event.getY(0); lastEvent[3] = event.getY(1); d = rotation(event); break; case MotionEvent.ACTION_UP: isZoomAndRotate = false; if (mode == DRAG) { float x = event.getX(); float y = event.getY(); } case MotionEvent.ACTION_OUTSIDE: isOutSide = true; mode = NONE; lastEvent = null; case MotionEvent.ACTION_POINTER_UP: mode = NONE; lastEvent = null; break; case MotionEvent.ACTION_MOVE: if (!isOutSide) { if (mode == DRAG) { isZoomAndRotate = false; view.animate().x(event.getRawX() + xCoOrdinate).y(event.getRawY() + yCoOrdinate).setDuration(0).start(); } if (mode == ZOOM && event.getPointerCount() == 2) { float newDist1 = spacing(event); if (newDist1 > 10f) { float scale = newDist1 / oldDist * view.getScaleX(); view.setScaleX(scale); view.setScaleY(scale); } if (lastEvent != null) { newRot = rotation(event); view.setRotation((float) (view.getRotation() + (newRot - d))); } } } break; } } private float rotation(MotionEvent event) { double delta_x = (event.getX(0) - event.getX(1)); double delta_y = (event.getY(0) - event.getY(1)); double radians = Math.atan2(delta_y, delta_x); return (float) Math.toDegrees(radians); } private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (int) Math.sqrt(x * x + y * y); } 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); } } 

//========================Just pass any view which you want to zoom/rotate/drag to viewTransformation() method. Very applicable for textview zoom. It will not pixelate text.

Essayez ce qui suit:

 package com.example.nwssugeoinformationmobileapplication; import android.os.Bundle; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.util.FloatMath; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View.OnTouchListener; import android.widget.TabHost; import android.widget.TabHost.TabSpec; import android.graphics.Masortingx; import android.graphics.PointF; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ImageView; public class MainActivity extends Activity implements OnTouchListener { private static final Ssortingng TAG = "Touch"; Masortingx masortingx = new Masortingx(); Masortingx savedMasortingx = new Masortingx(); static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; PointF start = new PointF(); PointF mid = new PointF(); float oldDist = 1f; private ImageView view; private float[] masortingxValues = new float[9]; private float maxZoom; private float minZoom; private float height; private float width; private RectF viewRect; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TabHost th = (TabHost) findViewById (R.id.tabhost); th.setup(); TabSpec specs = th.newTabSpec("tag1"); specs.setContent(R.id.tab1); specs.setIndicator("Map"); th.addTab(specs); specs = th.newTabSpec("tag2"); specs.setContent(R.id.tab2); specs.setIndicator("Search"); th.addTab(specs); view = (ImageView) findViewById(R.id.imageView1); Drawable bitmap = getResources().getDrawable(R.drawable.map); view.setImageDrawable(bitmap); view.setOnTouchListener(this); masortingx.setTranslate(1f, 1f); view.setImageMasortingx(masortingx); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if(hasFocus){ init(); } } private void init() { maxZoom = 2; minZoom = 1f; height = view.getDrawable().getInsortingnsicHeight(); width = view.getDrawable().getInsortingnsicWidth(); viewRect = new RectF(0, 0, view.getWidth(), view.getHeight()); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menus, menu); return true; } public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()== R.id.item1){ Log.d("Tracks", "Track Us was Clicked"); startActivity(new Intent (MainActivity.this, Tracklocation.class )); } if(item.getItemId()== R.id.item2){ Log.d("Updates", "Updates was Clicked"); startActivity(new Intent (MainActivity.this, Updates.class )); } if(item.getItemId()== R.id.item3){ Log.d("About Us", "About Us was Clicked"); startActivity(new Intent (MainActivity.this, Horoscope.class )); } return super.onOptionsItemSelected(item); } @Override public boolean onTouch(View v, MotionEvent rawEvent) { ImageView view = (ImageView) v; view.setScaleType(ImageView.ScaleType.MATRIX); dumpEvent(rawEvent); // Handle touch events here... switch (rawEvent.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMasortingx.set(masortingx); start.set(rawEvent.getX(), rawEvent.getY()); Log.d(TAG, "mode=DRAG"); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(rawEvent); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 10f) { savedMasortingx.set(masortingx); midPoint(mid, rawEvent); 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) { masortingx.set(savedMasortingx); // limit pan masortingx.getValues(masortingxValues); float currentY = masortingxValues[Masortingx.MTRANS_Y]; float currentX = masortingxValues[Masortingx.MTRANS_X]; float currentScale = masortingxValues[Masortingx.MSCALE_X]; float currentHeight = height * currentScale; float currentWidth = width * currentScale; float dx = rawEvent.getX() - start.x; float dy = rawEvent.getY() - start.y; float newX = currentX+dx; float newY = currentY+dy; RectF drawingRect = new RectF(newX, newY, newX+currentWidth, newY+currentHeight); float diffUp = Math.min(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top); float diffDown = Math.max(viewRect.bottom-drawingRect.bottom, viewRect.top-drawingRect.top); float diffLeft = Math.min(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right); float diffRight = Math.max(viewRect.left-drawingRect.left, viewRect.right-drawingRect.right); if(diffUp > 0 ){ dy +=diffUp; } if(diffDown < 0){ dy +=diffDown; } if( diffLeft> 0){ dx += diffLeft; } if(diffRight < 0){ dx += diffRight; } matrix.postTranslate(dx, dy); } else if (mode == ZOOM) { float newDist = spacing(rawEvent); Log.d(TAG, "newDist=" + newDist); if (newDist > 10f) { masortingx.set(savedMasortingx); float scale1 = newDist / oldDist; masortingx.getValues(masortingxValues); float currentScale = masortingxValues[Masortingx.MSCALE_X]; // limit zoom if (scale1 * currentScale > maxZoom) { scale1 = maxZoom / currentScale; } else if (scale1 * currentScale < minZoom) { scale1 = minZoom / currentScale; } matrix.postScale(scale1, scale1, mid.x, mid.y); } } break; } view.setImageMatrix(matrix); return true; } @SuppressWarnings("deprecation") 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 */ @SuppressLint("FloatMath") 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); } } 

I needed something similar, but needed the ability to get the dimensions easily and also drag/drop. I based this off of the answer @Nicolas Tyler gave and modified it from there.

The features are pinch zoom in/out, long press to vibration/highlighted drag/drop.

To use it add this CustomZoomView class to your project.

 public class CustomZoomView extends View implements View.OnTouchListener, View.OnLongClickListener{ private Paint mPaint; Vibrator v; static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; static final int MOVE = 3; private int mode = NONE; Rect src; Rect mTempDst = new Rect(); Rect dst = new Rect(); Bitmap mBitmap; private int mBitmapWidth = -1; private int mBitmapHeight = -1; private PointF mStartPoint = new PointF(); private PointF mMiddlePoint = new PointF(); private PointF mStartDragPoint = new PointF(); private PointF mMovePoint = new PointF(); private float oldDist = 1f; private float scale; private float oldEventX = 0; private float oldEventY = 0; private float oldStartPointX = 0; private float oldStartPointY = 0; private int mViewWidth = -1; private int mViewHeight = -1; private boolean mDraggable = false; public CustomZoomView(Context context) { this(context, null, 0); } public CustomZoomView(Context context, AtsortingbuteSet attrs) { this(context, attrs, 0); } public CustomZoomView(Context context, AtsortingbuteSet attrs, int defStyle) { super(context, attrs, defStyle); this.setOnTouchListener(this); this.setOnLongClickListener(this); v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mPaint = new Paint(); mPaint.setColorFilter(new PorterDuffColorFilter(Color.argb(100,255,255,255), PorterDuff.Mode.SRC_IN)); } @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; mViewHeight = h; } public void setBitmap(Bitmap bitmap) { if (bitmap != null) { src = new Rect(); src.left = 0; src.top = 0; src.right = bitmap.getWidth(); src.bottom = bitmap.getHeight(); mBitmap = bitmap; mBitmapWidth = bitmap.getWidth() * 1; mBitmapHeight = bitmap.getHeight() * 1; dst = new Rect(); dst.left = (mViewWidth / 2) - (mBitmapWidth / 2); dst.top = (mViewHeight / 2) - (mBitmapHeight / 2); dst.right = (mViewWidth / 2) + (mBitmapWidth / 2); dst.bottom = (mViewHeight / 2) + (mBitmapHeight / 2); } } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: mStartPoint.set(event.getX(), event.getY()); mStartDragPoint.set(event.getX(), event.getY()); mTempDst.set(dst.left, dst.top, dst.right, dst.bottom); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); if (oldDist > 10f) { midPoint(mMiddlePoint, event); mode = ZOOM; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: if (mode == ZOOM) { mBitmapWidth = dst.right - dst.left; mBitmapHeight = dst.bottom - dst.top; } mode = NONE; break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { mMovePoint.x = event.getX(); mMovePoint.y = event.getY(); drag(event); } else if (mode == ZOOM) { zoom(event); } else if (mode == MOVE) { move(event); } break; } return false; } public void move(MotionEvent event) { int xChange = (int) (event.getX() - mStartPoint.x); int yChange = (int) (event.getY() - mStartPoint.y); dst.left = mTempDst.left + (xChange); dst.top = mTempDst.top + (yChange); dst.right = mTempDst.right + (xChange); dst.bottom = mTempDst.bottom + (yChange); invalidate(); } public void drag(MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); float spacingX = eventX - mStartDragPoint.x; float spacingY = eventY - mStartDragPoint.y; float newPositionLeft = (dst.left < 0 ? spacingX : spacingX * -1) + dst.left; float newPositionRight = (spacingX) + dst.right; float newPositionTop = (dst.top < 0 ? spacingY : spacingY * -1) + dst.top; float newPositionBottom = (spacingY) + dst.bottom; boolean x = true; boolean y = true; if (newPositionRight < 0.0f || newPositionLeft > 0.0f) { if (newPositionRight < 0.0f && newPositionLeft > 0.0f) { x = false; } else { eventX = oldEventX; mStartDragPoint.x = oldStartPointX; } } if (newPositionBottom < 0.0f || newPositionTop > 0.0f) { if (newPositionBottom < 0.0f && newPositionTop > 0.0f) { y = false; } else { eventY = oldEventY; mStartDragPoint.y = oldStartPointY; } } if (mDraggable) { if (x) oldEventX = eventX; if (y) oldEventY = eventY; if (x) oldStartPointX = mStartDragPoint.x; if (y) oldStartPointY = mStartDragPoint.y; } } public void zoom(MotionEvent event) { float newDist = spacing(event); boolean in = newDist > oldDist; if (!in && scale < .01f) { return; } scale = newDist / oldDist; int xChange = (int) ((mBitmapWidth * scale) / 2); int yChange = (int) ((mBitmapHeight * scale) / 2); if (xChange > 10 && yChange > 10) { //ADDED THIS TO KEEP IT FROM GOING INVERSE int xMidPoint = ((dst.right - dst.left) / 2) + dst.left; int yMidPoint = ((dst.bottom - dst.top) / 2) + dst.top; dst.left = (int) (float) (xMidPoint - xChange); dst.top = (int) (float) (yMidPoint - yChange); dst.right = (int) (float) (xMidPoint + xChange); dst.bottom = (int) (float) (yMidPoint + yChange); } invalidate(); } /** * 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 (float) Math.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); } @Override public boolean onLongClick(View view) { if (mode == DRAG) { if ((mStartPoint.x > dst.left && mStartPoint.x < dst.right) && (mStartPoint.y < dst.bottom && mStartPoint.y > dst.top) && (mMovePoint.x > dst.left && mMovePoint.x < dst.right) && (mMovePoint.y < dst.bottom && mMovePoint.y > dst.top)) { mode = MOVE; v.vibrate(500); } } return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mode == MOVE) { canvas.drawBitmap(mBitmap, src, dst, null); canvas.drawBitmap(mBitmap, src, dst, mPaint); } else { canvas.drawBitmap(mBitmap, src, dst, null); } } } 

…then add this to your activity

 CustomZoomView customImageView = (CustomZoomView) findViewById(R.id.customZoomView); customImageView.setBitmap(yourBitmap); 

…and this in your view in xml.

  

…and add this to your manifest

  

Here is my solution, it is based on @alexbirkett’s solution.

 public class ZoomImageView extends ImageView { // region . Static fields . static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; static final int CLICK = 3; // endregion . Static fields . // region . Fields . private int mode = NONE; private Masortingx mMasortingx = new Masortingx(); private PointF mLastTouch = new PointF(); private PointF mStartTouch = new PointF(); private float minScale = 0.5f; private float maxScale = 4f; private float[] mCriticPoints; private float mScale = 1f; private float mRight; private float mBottom; private float mOriginalBitmapWidth; private float mOriginalBitmapHeight; private ScaleGestureDetector mScaleDetector; //endregion . Fields . // region . Ctor . public ZoomImageView(Context context) { super(context); init(context); } public ZoomImageView(Context context, AtsortingbuteSet attrs) { super(context, attrs); init(context); } public ZoomImageView(Context context, AtsortingbuteSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } // endregion . Ctor . // region . Overrider . @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int bmHeight = getBmHeight(); int bmWidth = getBmWidth(); float width = getMeasuredWidth(); float height = getMeasuredHeight(); float scale = 1; // If image is bigger then display fit it to screen. if (width < bmWidth || height < bmHeight) { scale = width > height ? height / bmHeight : width / bmWidth; } mMasortingx.setScale(scale, scale); mScale = 1f; mOriginalBitmapWidth = scale * bmWidth; mOriginalBitmapHeight = scale * bmHeight; // Center the image float redundantYSpace = (height - mOriginalBitmapHeight); float redundantXSpace = (width - mOriginalBitmapWidth); mMasortingx.postTranslate(redundantXSpace / 2, redundantYSpace / 2); setImageMasortingx(mMasortingx); } @Override public boolean onTouchEvent(MotionEvent event) { mScaleDetector.onTouchEvent(event); mMasortingx.getValues(mCriticPoints); float translateX = mCriticPoints[Masortingx.MTRANS_X]; float trnslateY = mCriticPoints[Masortingx.MTRANS_Y]; PointF currentPoint = new PointF(event.getX(), event.getY()); switch (event.getAction()) { //when one finger is touching //set the mode to DRAG case MotionEvent.ACTION_DOWN: mLastTouch.set(event.getX(), event.getY()); mStartTouch.set(mLastTouch); mode = DRAG; break; //when two fingers are touching //set the mode to ZOOM case MotionEvent.ACTION_POINTER_DOWN: mLastTouch.set(event.getX(), event.getY()); mStartTouch.set(mLastTouch); mode = ZOOM; break; //when a finger moves //If mode is applicable move image case MotionEvent.ACTION_MOVE: //if the mode is ZOOM or //if the mode is DRAG and already zoomed if (mode == ZOOM || (mode == DRAG && mScale > minScale)) { // region . Move image. float deltaX = currentPoint.x - mLastTouch.x;// x difference float deltaY = currentPoint.y - mLastTouch.y;// y difference float scaleWidth = Math.round(mOriginalBitmapWidth * mScale);// width after applying current scale float scaleHeight = Math.round(mOriginalBitmapHeight * mScale);// height after applying current scale // Move image to lef or right if its width is bigger than display width if (scaleWidth > getWidth()) { if (translateX + deltaX > 0) { deltaX = -translateX; } else if (translateX + deltaX < -mRight) { deltaX = -(translateX + mRight); } } else { deltaX = 0; } // Move image to up or bottom if its height is bigger than display height if (scaleHeight > getHeight()) { if (trnslateY + deltaY > 0) { deltaY = -trnslateY; } else if (trnslateY + deltaY < -mBottom) { deltaY = -(trnslateY + mBottom); } } else { deltaY = 0; } //move the image with the matrix mMatrix.postTranslate(deltaX, deltaY); //set the last touch location to the current mLastTouch.set(currentPoint.x, currentPoint.y); // endregion . Move image . } break; //first finger is lifted case MotionEvent.ACTION_UP: mode = NONE; int xDiff = (int) Math.abs(currentPoint.x - mStartTouch.x); int yDiff = (int) Math.abs(currentPoint.y - mStartTouch.y); if (xDiff < CLICK && yDiff < CLICK) performClick(); break; // second finger is lifted case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; } setImageMatrix(mMatrix); invalidate(); return true; } //endregion . Overrides . // region . Privates . private void init(Context context) { super.setClickable(true); mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); mCriticPoints = new float[9]; setImageMatrix(mMatrix); setScaleType(ScaleType.MATRIX); } private int getBmWidth() { Drawable drawable = getDrawable(); if (drawable != null) { return drawable.getIntrinsicWidth(); } return 0; } private int getBmHeight() { Drawable drawable = getDrawable(); if (drawable != null) { return drawable.getIntrinsicHeight(); } return 0; } //endregion . Privates . // region . Internal classes . private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mode = ZOOM; return true; } @Override public boolean onScale(ScaleGestureDetector detector) { float scaleFactor = detector.getScaleFactor(); float newScale = mScale * scaleFactor; if (newScale < maxScale && newScale > minScale) { mScale = newScale; float width = getWidth(); float height = getHeight(); mRight = (mOriginalBitmapWidth * mScale) - width; mBottom = (mOriginalBitmapHeight * mScale) - height; float scaledBitmapWidth = mOriginalBitmapWidth * mScale; float scaledBitmapHeight = mOriginalBitmapHeight * mScale; if (scaledBitmapWidth < = width || scaledBitmapHeight <= height) { mMatrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2); } else { mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); } } return true; } } // endregion . Internal classes . } 

Method to call the About&support dialog

  public void setupAboutSupport() { try { // The About&Support AlertDialog is active activeAboutSupport=true; View messageView; int orientation=this.getResources().getConfiguration().orientation; // Inflate the about message contents messageView = getLayoutInflater().inflate(R.layout.about_support, null, false); ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.MyCustomTheme_AlertDialog1); AlertDialog.Builder builder = new AlertDialog.Builder(ctw); builder.setIcon(R.mipmap.ic_launcher); builder.setTitle(R.ssortingng.action_aboutSupport); builder.setView(messageView); TouchImageView imgDisplay = (TouchImageView) messageView.findViewById(R.id.action_infolinks_about_support); imgDisplay.setMaxZoom(3f); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.myinfolinks_about_support); int imageWidth = bitmap.getWidth(); int imageHeight = bitmap.getHeight(); int newWidth; // Calculate the new About_Support image width if(orientation==Configuration.ORIENTATION_PORTRAIT ) { // For 7" up to 10" tablets //if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) { if (SingletonMyInfoLinks.isTablet) { // newWidth = widthScreen - (two borders of about_support layout and 20% of width Screen) newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.2)); } else newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.1)); } else { // For 7" up to 10" tablets //if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) { if (SingletonMyInfoLinks.isTablet) { newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.5)); } else newWidth = widthScreen - ((2 * toPixels(8)) + (int)(widthScreen*0.3)); } // Get the scale factor float scaleFactor = (float)newWidth/(float)imageWidth; // Calculate the new About_Support image height int newHeight = (int)(imageHeight * scaleFactor); // Set the new bitmap corresponding the adjusted About_Support image bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); // Rescale the image imgDisplay.setImageBitmap(bitmap); dialogAboutSupport = builder.show(); TextView textViewVersion = (TextView) dialogAboutSupport.findViewById(R.id.action_strVersion); textViewVersion.setText(Html.fromHtml(getSsortingng(R.ssortingng.aboutSupport_text1)+" "+versionName+"")); TextView textViewDeveloperName = (TextView) dialogAboutSupport.findViewById(R.id.action_strDeveloperName); textViewDeveloperName.setText(Html.fromHtml(getSsortingng(R.ssortingng.aboutSupport_text2)+" "+SingletonMyInfoLinks.developerName+"")); TextView textViewSupportEmail = (TextView) dialogAboutSupport.findViewById(R.id.action_strSupportEmail); textViewSupportEmail.setText(Html.fromHtml(getSsortingng(R.ssortingng.aboutSupport_text3)+" "+SingletonMyInfoLinks.developerEmail)); TextView textViewCompanyName = (TextView) dialogAboutSupport.findViewById(R.id.action_strCompanyName); textViewCompanyName.setText(Html.fromHtml(getSsortingng(R.ssortingng.aboutSupport_text4)+" "+SingletonMyInfoLinks.companyName)); Button btnOk = (Button) dialogAboutSupport.findViewById(R.id.btnOK); btnOk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialogAboutSupport.dismiss(); } }); dialogAboutSupport.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(final DialogInterface dialog) { // the About & Support AlertDialog is closed activeAboutSupport=false; } }); dialogAboutSupport.getWindow().setBackgroundDrawable(new ColorDrawable(SingletonMyInfoLinks.atualBackgroundColor)); /* Effect that image appear slower */ // Only the fade_in matters AlphaAnimation fade_out = new AlphaAnimation(1.0f, 0.0f); AlphaAnimation fade_in = new AlphaAnimation(0.0f, 1.0f); AlphaAnimation a = false ? fade_out : fade_in; a.setDuration(2000); // 2 sec a.setFillAfter(true); // Maintain the visibility at the end of animation // Animation start ImageView img = (ImageView) messageView.findViewById(R.id.action_infolinks_about_support); img.startAnimation(a); } catch (Exception e) { //Log.e(SingletonMyInfoLinks.appNameText +"-" + getLocalClassName() + ": ", e.getMessage()); } } 

ZoomLib Link: https://drive.google.com/uc?export=download&id=0B34PUThnUsjVaHpkaGk0Z1hSRU0

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dummy_layout_for_zooming);// Activity layout mZoomLinearLayout = (LinearLayout) findViewById(R.id.mZoomLinearLayout);// LinearLayout inside Activity layout View v = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.layout_for_zoom, null, false);// View wants to zoom v.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT)); ZoomView zoomView = new ZoomView(this);// intialize lib zoomView.addView(v); mZoomLinearLayout.addView(zoomView); } 

Just change ACTION_MOVE_EVENT in Chirag Raval Answer to set ZOOM_IN LIMIT

 float[] values = new float[9]; masortingx.getValues(values); //0.37047964 is limit for zoom in if(values[Masortingx.MSCALE_X]>0.37047964) { masortingx.set(savedMasortingx); masortingx.postScale(scale, scale, mid.x, mid.y); view.setImageMasortingx(masortingx); }else if (scale>1){ masortingx.set(savedMasortingx); masortingx.postScale(scale, scale, mid.x, mid.y); view.setImageMasortingx(masortingx); } 

I know it is a bit late for this answer, but I hope it helps someone.

I was looking for the same thing (Zoom using pinch, and dragging image) and I found this Android Developers Blog link .

Fonctionne parfaitement. No artifacts or what so ever. It uses ScaleGestureDetector .

If you want to set scale of an image before showing, use this class: https://github.com/MikeOrtiz/TouchImageView/blob/master/src/com/ortiz/touch/TouchImageView.java .

Also the image can be resized with double tap.

If you use the ImageView inside a ViewPager , apply this fix: https://github.com/MikeOrtiz/TouchImageView/issues/125 .

I am Using this one it is working perfectly.

  

My a MyZoomableImageViewTouch class is below:

 public class MyZoomableImageViewTouch extends ImageViewTouch { static final float SCROLL_DELTA_THRESHOLD = 1.0f; public MyZoomableImageViewTouch(Context context, AtsortingbuteSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public MyZoomableImageViewTouch(Context context, AtsortingbuteSet attrs) { super(context, attrs); init(); } public MyZoomableImageViewTouch(Context context) { super(context); init(); } private void init() { View.OnTouchListener listener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (getScale() > 1f) { getParent().requestDisallowInterceptTouchEvent(true); } else { getParent().requestDisallowInterceptTouchEvent(false); } return false; } }; setOnTouchListener(listener); setDisplayType(DisplayType.FIT_TO_SCREEN); } @Override protected float onDoubleTapPost(float scale, float maxZoom) { if (scale != 1f) { mDoubleTapDirection = 1; return 1f; } if (mDoubleTapDirection == 1) { mDoubleTapDirection = -1; if ((scale + (mScaleFactor * 2)) < = maxZoom) { return scale + mScaleFactor; } else { mDoubleTapDirection = -1; return maxZoom; } } else { mDoubleTapDirection = 1; return 1f; } } @Override public boolean canScroll(int direction) { RectF bitmapRect = getBitmapRect(); updateRect(bitmapRect, mScrollRect); Rect imageViewRect = new Rect(); getGlobalVisibleRect(imageViewRect); if (null == bitmapRect) { return false; } if (Math.abs(bitmapRect.right - imageViewRect.right) < SCROLL_DELTA_THRESHOLD) { if (direction < 0) { return false; } } if (Math.abs(bitmapRect.left - mScrollRect.left) < SCROLL_DELTA_THRESHOLD) { if (direction > 0) { return false; } } return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (getScale() == 1f) return false; if (distanceX != 0 && !canScroll((int) -distanceX)) { getParent().requestDisallowInterceptTouchEvent(false); return false; } else { getParent().requestDisallowInterceptTouchEvent(true); mUserScaled = true; scrollBy(-distanceX, -distanceY); invalidate(); return true; } } }