Увеличение и уменьшение масштаба изображения в Android

Привет, я новичок в приложении для Android. Я хочу использовать Zoom-in и Zoom-out ImageView. Я пробовал большую часть образца, но во всем этом изображении в представлении изображения появляется Zoom-in и Zoom-out. Я хочу, чтобы Zoom-in и Уменьшение ImageView. Я хочу увеличить ширину и высоту изображения во время Zoom-in и уменьшить ширину и высоту изображения в режиме Zoom-out. Может ли кто-нибудь предложить мне?

Сделайте два класса java

Класс масштабирования

 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; } } 

Сделать второй класс

 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)); } } 

Следуйте приведенному ниже классу, который используется для увеличения и уменьшения масштаба для ImageView.

 import android.app.Activity; import android.graphics.Matrix; import android.graphics.PointF; import android.os.Bundle; import android.util.FloatMath; 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 String TAG = "Touch"; @SuppressWarnings("unused") private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f; // These matrices will be used to scale points of the image Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); // 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 savedMatrix.set(matrix); 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) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points } else if (mode == ZOOM) { // pinch zooming float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 5f) { matrix.set(savedMatrix); scale = newDist / oldDist; // setting the scaling of the // matrix...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 FloatMath.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()); } } 

У других реализаций у всех есть своего рода недостаток. Поэтому я в основном перепутал их и придумал это.

Создайте собственное пользовательское представление:

ZoomableImageView.java:

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.PointF; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.widget.ImageView; public class ZoomableImageView extends ImageView { Matrix matrix = new Matrix(); 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, AttributeSet attr) { super(context, attr); super.setClickable(true); this.context = context; mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); matrix.setTranslate(1f, 1f); m = new float[9]; setImageMatrix(matrix); setScaleType(ScaleType.MATRIX); setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mScaleDetector.onTouchEvent(event); matrix.getValues(m); float x = m[Matrix.MTRANS_X]; float y = m[Matrix.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) matrix.postTranslate(0, -y); } else { if (x < -right) matrix.postTranslate(-(x + right), 0); else if (x > 0) matrix.postTranslate(-x, 0); } } } } else { matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY()); matrix.getValues(m); float x = m[Matrix.MTRANS_X]; float y = m[Matrix.MTRANS_Y]; if (mScaleFactor < 1) { if (x < -right) matrix.postTranslate(-(x + right), 0); else if (x > 0) matrix.postTranslate(-x, 0); if (y < -bottom) matrix.postTranslate(0, -(y + bottom)); else if (y > 0) matrix.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); matrix.setScale(scale, scale); setImageMatrix(matrix); saveScale = 1f; // Center the image redundantYSpace = height - (scale * bmHeight) ; redundantXSpace = width - (scale * bmWidth); redundantYSpace /= 2; redundantXSpace /= 2; matrix.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); setImageMatrix(matrix); } } 

Затем добавьте изображение следующим образом:

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

Добавьте представление, подобное этому в XML:

 <PACKAGE.ZoomableImageView android:id="@+id/IMAGEID" android:layout_width="match_parent" android:layout_height="match_parent"/> 

Просто используйте этот класс: TouchImageView

Это еще одна реализация, основанная на кодексе, опубликованном Николасом Тайлером.

Исправлены следующие ошибки:

  • Установка minScale на число меньше 1 теперь работает
  • Вам не нужно использовать setImageBitmap() для установки изображения (вы можете использовать, например, setImageResource()
  • Все конструкторы теперь работают правильно

Следующие вещи, среди прочих, приведены в порядок:

  • OnTouchListener не используется, это необязательно, потому что класс может просто реализовать метод onTouchEvent() .

  • Назначение right = width * saveScale - width - (2 * redundantXSpace * saveScale); Было упрощено до right = (originalBitmapWidth * saveScale) - width который, по моему варианту, намного менее запутан.

  • Некоторые переменные-члены удаляются (возможно, из этого класса можно удалить больше состояний)

Это не идеально, но здесь вы идете:

 import android.content.Context; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; 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; matrix.setScale(scale, scale); saveScale = 1f; originalBitmapWidth = scale * bmWidth; originalBitmapHeight = scale * bmHeight; // Center the image redundantYSpace = (height - originalBitmapHeight); redundantXSpace = (width - originalBitmapWidth); matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2); setImageMatrix(matrix); } @Override public boolean onTouchEvent(MotionEvent event) { mScaleDetector.onTouchEvent(event); matrix.getValues(m); float x = m[Matrix.MTRANS_X]; float y = m[Matrix.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; } } 

Я сделал свое собственное изображение с максимальным увеличением. Для кода Чирага Раваля нет ограничений / границ, поэтому пользователь может перетащить изображение с экрана.

Вот класс CustomImageView:

  public class CustomImageVIew extends ImageView implements OnTouchListener { private Matrix matrix = new Matrix(); private Matrix savedMatrix = new Matrix(); 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 matrixValues[] = {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, AttributeSet attrs) { this(context, attrs, 0); } public CustomImageVIew(Context context, AttributeSet 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); matrix.postTranslate(mBitmapMiddlePoint.x, mBitmapMiddlePoint.y); this.setImageMatrix(matrix); } } @Override public boolean onTouch(View v, MotionEvent event){ switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); mStartPoint.set(event.getX(), event.getY()); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); if(oldDist > 10f){ savedMatrix.set(matrix); 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){ matrix.getValues(matrixValues); float left = matrixValues[2]; float top = matrixValues[5]; float bottom = (top + (matrixValues[0] * mBitmapHeight)) - mViewHeight; float right = (left + (matrixValues[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){ matrix.set(savedMatrix); matrix.postTranslate(x? eventX - mStartPoint.x : 0, y? eventY - mStartPoint.y : 0); this.setImageMatrix(matrix); if(x)oldEventX = eventX; if(y)oldEventY = eventY; if(x)oldStartPointX = mStartPoint.x; if(y)oldStartPointY = mStartPoint.y; } } public void zoom(MotionEvent event){ matrix.getValues(matrixValues); float newDist = spacing(event); float bitmapWidth = matrixValues[0] * mBitmapWidth; float bimtapHeight = matrixValues[0] * mBitmapHeight; boolean in = newDist > oldDist; if(!in && matrixValues[0] < 1){ return; } if(bitmapWidth > mViewWidth || bimtapHeight > mViewHeight){ mDraggable = true; } else{ mDraggable = false; } float midX = (mViewWidth / 2); float midY = (mViewHeight / 2); matrix.set(savedMatrix); scale = newDist / oldDist; matrix.postScale(scale, scale, bitmapWidth > mViewWidth ? mMiddlePoint.x : midX, bimtapHeight > mViewHeight ? mMiddlePoint.y : midY); this.setImageMatrix(matrix); } /** 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); } } 

Так вы можете использовать его в своей деятельности:

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

И макет:

 <your.package.name.CustomImageVIew android:id="@+id/customImageVIew1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginBottom="15dp" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginTop="15dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:scaleType="matrix"/> // important 

Я получил самый полезный ответ от @Nicolas Tyler, но у меня были проблемы с работой синтаксиса и логики. Я также не хотел никакого пространства Альфы, и моя Алгебра была ржавой! Через 3 дня я собрал свою версию.

Мой ответ отличается от @Nicolas Tyler следующим:

  1. Различные имена переменных, которые я нашел, имели больше смысла в базовом контекстующем использовании

  2. Этот класс изображения Pinch-Zoom НЕ отображает альфа-пространство и позволит вам увеличивать и уменьшать масштаб и не пропускать изображение под кадром и отображать альфа-пространство

  3. Добавлены глубокие комментарии к разделу матрицы, чтобы объяснить, что происходит с математикой

  4. Этот класс изображений также позволит вам перейти в resourceId и создать из него растровое изображение

  5. Гораздо более простые алгоритмы как для масштабирования, так и для перевода и нескольких переменных

  6. Изменение изображения внутри этого приведет к тому, что он будет увеличивать / уменьшать масштаб, так что новое изображение занимает контейнер представления

Подробное обновление ресурсов в Алгебре можно найти здесь: https://youtu.be/IiXB6tYtY4w?t=4m12s Это видео охватывает ядро ​​матриц Scalar и Translation (и поможет вам разобраться в материалах MTRANS_X и MTRANS_Y). Если у вас возникнут вопросы, и я сделаю все возможное, чтобы ответить (но я НЕ эксперт по алгебре).

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; 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; Matrix _matrix = new Matrix(); 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 matrix is not setting the values from the arrayOf9Floats, but rather taking the //matrix values and assigning them into the arrayOf9Floats. I extremely dislike this syntax and I think //it should have been written as _arrayOf9Floats = _matrix.getValues() but that's Android for you!!! _matrix.getValues(_arrayOf9Floats); //Look at https://youtu.be/IiXB6tYtY4w?t=4m12s , it shows scale, rotate, and translate matrices //If you look at the translate matrix, 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[Matrix.MTRANS_X]; float yTranslate = _arrayOf9Floats[Matrix.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 matrix 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;} } 

Этот код работает и реализует двойное нажатие, чтобы вернуться к исходному размеру изображения.

1-й шаг. В вашем макете xml поставьте это:

 <com.****.*****.TouchImageView android:id="@+id/action_infolinks_splash" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@mipmap/myinfolinks_splash" android:layout_gravity="center" android:gravity="center" android:scaleType="fitCenter" android:contentDescription="@string/aboutSupport_description_image"/> 

Шаг 2. Создайте файл (TouchImageView.java) с помощью класса TouchImageView:

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.PointF; import android.util.AttributeSet; 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 { Matrix 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 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, AttributeSet attrs) { super(context, attrs); sharedConstructing(context); } private void sharedConstructing(Context context) { super.setClickable(true); this.context = context; mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); matrix = new Matrix(); m = new float[9]; setImageMatrix(matrix); 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; matrix = new Matrix(); matrix.setScale(origScale, origScale); matrix.postTranslate(origRedundantXSpace, origRedundantYSpace); setImageMatrix(matrix); 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); matrix.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(); } } 

И, наконец, сделайте звонок в своей основной деятельности:

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

Я видел много кода, и после моих настроек он работает. Наслаждайтесь!

Я думаю, что ответ Чирага Раваля замечательный!

Единственное, что можно было бы улучшить, – это переместить весь этот код внутри какого-либо класса, например:

 PinchZoomImageView extends ImageView {... 

И добавление исходной инициализации матрицы изображений для предотвращения масштабирования после первого нажатия:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); matrix = new Matrix(this.getImageMatrix()); } 

Кстати, это исправит ошибку, о которой говорили Мухаммед Умар и Баз

PS Также могут быть полезны PS с ограничениями масштабирования Max и Min. Например, макс. Зум – 2X, а min zoom – исходная шкала, когда изображение установлено на экране:

 static final int MAX_SCALE_FACTOR = 2; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Getting initial Image matrix mViewMatrix = new Matrix(this.getImageMatrix()); mMinScaleMatrix = new Matrix(mViewMatrix); float initialScale = getMatrixScale(mViewMatrix); 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) { downscaleMatrix(resScale, mViewMatrix); } 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) { mCurSavedMatrix.set(mViewMatrix); midPoint(mCurMidPoint, event); mCurrentMode = ZOOM; Helper.LOGD(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_MOVE: if (mCurrentMode == DRAG) { mViewMatrix.set(mCurSavedMatrix); mViewMatrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points } else if (mCurrentMode == ZOOM) { // pinch zooming float newDist = spacing(event); Helper.LOGD(TAG, "newDist=" + newDist); if (newDist > 1.f) { mViewMatrix.set(mCurSavedMatrix); scale = newDist / mOldDist; // setting the scaling of the // matrix...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); } 

Простой способ:

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

Add below line in build.gradle :

 compile 'com.commit451:PhotoView:1.2.4' 

Попробуйте следующее:

 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.Matrix; 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 String TAG = "Touch"; Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); 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[] matrixValues = 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); matrix.setTranslate(1f, 1f); view.setImageMatrix(matrix); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if(hasFocus){ init(); } } private void init() { maxZoom = 2; minZoom = 1f; height = view.getDrawable().getIntrinsicHeight(); width = view.getDrawable().getIntrinsicWidth(); 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: savedMatrix.set(matrix); 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) { savedMatrix.set(matrix); 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) { matrix.set(savedMatrix); // limit pan matrix.getValues(matrixValues); float currentY = matrixValues[Matrix.MTRANS_Y]; float currentX = matrixValues[Matrix.MTRANS_X]; float currentScale = matrixValues[Matrix.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) { matrix.set(savedMatrix); float scale1 = newDist / oldDist; matrix.getValues(matrixValues); float currentScale = matrixValues[Matrix.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, AttributeSet attrs) { this(context, attrs, 0); } public CustomZoomView(Context context, AttributeSet 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.

 <your.package.name.CustomZoomView android:id="@+id/customZoomView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:longClickable="true"/> 

…and add this to your manifest

 <uses-permission android:name="android.permission.VIBRATE"/> 

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 Matrix mMatrix = new Matrix(); 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, AttributeSet attrs) { super(context, attrs); init(context); } public ZoomImageView(Context context, AttributeSet 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; } mMatrix.setScale(scale, scale); mScale = 1f; mOriginalBitmapWidth = scale * bmWidth; mOriginalBitmapHeight = scale * bmHeight; // Center the image float redundantYSpace = (height - mOriginalBitmapHeight); float redundantXSpace = (width - mOriginalBitmapWidth); mMatrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2); setImageMatrix(mMatrix); } @Override public boolean onTouchEvent(MotionEvent event) { mScaleDetector.onTouchEvent(event); mMatrix.getValues(mCriticPoints); float translateX = mCriticPoints[Matrix.MTRANS_X]; float trnslateY = mCriticPoints[Matrix.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.string.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(getString(R.string.aboutSupport_text1)+" <b>"+versionName+"</b>")); TextView textViewDeveloperName = (TextView) dialogAboutSupport.findViewById(R.id.action_strDeveloperName); textViewDeveloperName.setText(Html.fromHtml(getString(R.string.aboutSupport_text2)+" <b>"+SingletonMyInfoLinks.developerName+"</b>")); TextView textViewSupportEmail = (TextView) dialogAboutSupport.findViewById(R.id.action_strSupportEmail); textViewSupportEmail.setText(Html.fromHtml(getString(R.string.aboutSupport_text3)+" "+SingletonMyInfoLinks.developerEmail)); TextView textViewCompanyName = (TextView) dialogAboutSupport.findViewById(R.id.action_strCompanyName); textViewCompanyName.setText(Html.fromHtml(getString(R.string.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()); } } 

I am Using this one it is working perfectly.

 <your.packagename.MyZoomableImageViewTouch android:id="@+id/mediaImage" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="matrix"/> public class MyZoomableImageViewTouch extends ImageViewTouch { static final float SCROLL_DELTA_THRESHOLD = 1.0f; public MyZoomableImageViewTouch(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public MyZoomableImageViewTouch(Context context, AttributeSet 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; } } } 

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]; matrix.getValues(values); //0.37047964 is limit for zoom in if(values[Matrix.MSCALE_X]>0.37047964) { matrix.set(savedMatrix); matrix.postScale(scale, scale, mid.x, mid.y); view.setImageMatrix(matrix); }else if (scale>1){ matrix.set(savedMatrix); matrix.postScale(scale, scale, mid.x, mid.y); view.setImageMatrix(matrix); } 
Intereting Posts
Преобразование XML в объект JSON в Android Использовать список массивов объектов в качестве адаптера счетчика Файл Realm, созданный с Android в проекте, недействителен в другом MultiTouch android | Получение действия каждой точки касания Как я могу выровнять изображение внутри ImageView в нижней части ImageView? Android Bluetooth LE – характеристики чтения, не работающие на Samsung Арабские символы в String.Format ("% d", 1, Locale.US) Как изменить размер изображения gif в android Android – почему веб-просмотр перенаправляется на webbrowser Не удается опубликовать Android Alpha-тест, потому что рейтинг контента «In progress» FirebaseRecyclerAdapter не обновляет индексы элементов при удалении данных Как включить открытый ключ RSA в Google Play Services в моем бинарном приложении Android? Телефонная связь: исходный URL-адрес не указан в белом списке PopBackStack вызывает вызовы oncreateView фрагмента снова и снова Проверьте, есть ли у Android-устройства определенная аппаратная кнопка в коде