Android ImageView Zoom-in and Zoom-Out
Solution 1
Make two java classes
Zoom class
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;
}
}
make second class
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));
}
}
Solution 2
Please follow the below class, that is used for Zoom in and Zoom Out for ImageView.
import android.app.Activity;
import android.graphics.Matrix;
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 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
matrix.set(view.getImageMatrix());
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 (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());
}
}
Solution 3
The other implementations here all have some kind of a flaw. so i basically mixed them up and came up with this.
Create a custom view like this:
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);
}
}
Then add the image like this:
ZoomableImageView touch = (ZoomableImageView)findViewById(R.id.IMAGEID);
touch.setImageBitmap(bitmap);
Add the view like this in XML:
<PACKAGE.ZoomableImageView
android:id="@+id/IMAGEID"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Solution 4
Simple way:
PhotoViewAttacher pAttacher;
pAttacher = new PhotoViewAttacher(Your_Image_View);
pAttacher.update();
Add below line in build.gradle
:
compile 'com.commit451:PhotoView:1.2.4'
Solution 5
I have improved the answer I got from stack for flawless ZOOM (two finger) / ROTATION (two finger) / DRAG (Single finger).
//============================XML code==================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.flochat.imageviewzoomforstack.MainActivity">
<ImageView
android:id="@+id/imageview_trash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/trash" />
</LinearLayout>
//============================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.
karthi
Updated on February 02, 2022Comments
-
karthi over 2 years
I want to Zoom-in and Zoom-out an Android ImageView. I tried most of the samples but in all of them the image in the ImageView itself is getting Zoomed-in and Zoomed-out, while I want to Zoom-in and Zoom-out the ImageView. I want to increase the ImageView width and height while Zooming-in and reduce the ImageView width and height while Zooming-out. How do I achieve that?
-
chinna_82 almost 12 yearsi got error in... image=context.getResources().getDrawable(R.drawable.j); I copy an image in drawable folder. I renamed the image to j.. I got j cannot be resolved or is not a field..
-
Muhammad Umar over 11 yearswhenever i tap on image it zooms. what should i do to stop it
-
Baz over 11 yearsI would really appreciate an answer to the comment above. The same happens to me. Is there any way to stop it from zooming in on the first tap? The
ImageView
itself is set tocenterFit
. -
Shihab Uddin over 11 yearsgreat works by @Chirag Raval.. how can i add panning effects now?
-
KhalidTaha about 11 years@chinna_82, the image should be j.png and you should place it in Drawable folder. Then refresh your project and the error shouldn't be
-
Johann almost 11 yearsHas poor response and jumps all over the place.
-
Johann almost 11 yearsI've gone through over a dozen of these implementations and none of them have smooth behavior, including this one.
-
gta0004 almost 11 yearsFor some reason,
matrix = new Matrix(this.getImageMatrix());
line makes the image disappear for me. Do you know why? -
SysHex over 10 yearsOK, best implementation so far. My main issue with this implementation is that from the get go the image is displayed at 1:1 ratio and we cannot perform zoom out. Apart from that, it is my fav implementation thus far on this thread
-
jpm over 10 yearsWorks great for me too! Thanks for sharing!
-
jpm over 10 yearsAlthough I don't get why you write "fitCenter" works best, even though you call setScaleType(ScaleType.MATRIX) right in the constructor...? However. Thanks!
-
string.Empty over 10 yearsits up to you what scaletype you prefer.
-
anshul over 10 yearsDon' make fool of people who seek for an answer.This will not work if you change the scaletype to fitXy in the code where you have mentioned SCaleType to MATRIX.
-
string.Empty over 10 yearsI didn't say you should change the scaletype to fitXy... And if you change the code its not my fault that it does not work. I provided you with a working solution that i've used before.
-
jpm over 10 yearsHey @NicolasTyler , I'm using your solution and it works great! just one question: When I change the layout where the ZoomableImageView is in, the view is resized and updated but 'loses' its last state (zoom/position) (it's zoomed out to the initial state again). Do you know where it would be best to save the last state(matrix) and where to apply it again? (zooming and scrolling to the last position) Thanks!
-
string.Empty over 10 yearsAsk a new question and provide more info.
-
goRGon over 10 yearsIf you do it inside onMeasure() the matrix will just obtain the correct value according to current View zoom default scale. And this matrix will be used only after the next interaction with user (tap for example). And when did you image disappear?
-
Johnny Doe about 10 years@Baz, to avoid zooming on the first tap use
case MotionEvent.ACTION_DOWN: // first finger down only matrix.set(view.getImageMatrix()); savedMatrix.set(matrix);
This will copy current scaling settings to the initialmatrix
-
Chirag over 9 years@user1386213 yes, you can.
-
Omid Omidi over 9 yearsadd this: ViewTreeObserver vto = getViewTreeObserver(); vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { bmHeight = getMeasuredHeight(); bmWidth = getMeasuredWidth(); return true; } });
-
sravanalakshmi.sunkara about 9 yearsI was searching for matrix.set(view.getImageMatrix()); thanku @JohnnyDoe
-
Aggressor about 9 yearsThis looks great but I need to make some modifications and I wish it was commented :( Im brushing up on my Algebra but I've been stuck on this for two days. Any chance you could add comments, most notably to the onTouch sections and what 'saveScale' means?
-
string.Empty about 9 yearsI will add comments, but its not that complicated,
saveScale
is the current scale value of the image,minScale
being the smallest it can go andmaxScale
is the most the image can scale. -
Aggressor about 9 yearsThanks for the comments this is going to help immensely. I am going to attempt to get a different version of this pinch zoom added here to. Your solution is great for situations where you allow alpha space at max zoom out, I am designing a version where you cannot zoom past the minimum ratio that would lead to having alpha space.
-
Bullionist almost 9 yearsWorks like a charm. Thanks a lot.
-
Dusan Dimitrijevic almost 9 years@NicolasTyler And how would i use this class in some other package and activity?
-
Atul O Holic almost 9 years@Nicolas Can this zoom in and out achieved only by dragging like when I drag Image it zooms and when I drag out it resizes to original?
-
string.Empty almost 9 yearsI wrote this 2 years ago, i havent tested it but it was meant to be pinch zoom and drag to move image.
-
Can Canbek over 8 yearsHow do we keep the image in the screen? Because I can keep scrolling it until it is very much out of view.
-
moffeltje over 8 years@CanCanbek I think that is what this is supposed to do. You can ask a new question if you can't figure out how to do that.
-
Nagaraj Alagusundaram over 8 yearsFor those who use the above code, "return FloatMath.sqrt(x * x + y * y);" replace it with "return (float)Math.sqrt(x * x + y * y);" coz FloatMath is deprecated now. Cheers
-
Satheesh over 8 years@goRGon Hi, In my application i set image with fit to screen. And i want to zoom apart from screen size which is working fine. And I need to zoom out,drag,rotate the image which is done only outside of the screen not inside of the screen. pls help me how to do it.
-
Satheesh over 8 years@NicolasTyler Hi this is working fine what i want u gave here, thank you very much and i need image rotation with the same feature. could u please provide this as soon as possible.
-
YakirNa over 8 yearsWhat is the meaning of "alpha space"?
-
YakirNa over 8 yearsIt work's great and really is a much cleaner solution than the original. One thing you missed though is that the scale gesture always scale to the top left corner of the image, instead of in between the fingers. i'm going to try and fix it, so if you have any hints for me it would be much appreciated. Thanks!
-
YakirNa over 8 yearsI found that replacing
mMatrix.postScale(scaleFactor, scaleFactor);
withmMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
insidepublic boolean onScale(ScaleGestureDetector detector)
is doing the trick when you zoom in. more code is needed to support zoom out. but for now, it is enough for me. -
jmtsilva69 over 8 yearsFor better perform change this line: Bitmap bm = BitmapFactory.decodeResource(context.getResources(), R.mipmap.myinfolinks_splash); for this one: ImageView img = (ImageView) findViewById(R.id.action_infolinks_splash);
-
jmtsilva69 over 8 yearsAnd you don't need this (it's already set in the xml layout): imgDisplay.setImageResource(R.mipmap.myinfolinks_splash);
-
driftking9987 over 8 yearsCan anyone tell me how to initialize it? In mainactivity. I removed
android:src
andandroid:scaleType
from the xml file. How to add the image which is in "drawable" folder to it. -
jmtsilva69 over 8 yearsSkizo- this: ImageView img = (ImageView) findViewById(R.id.action_infolinks_splash)
-
jmtsilva69 over 8 yearsSkizo- this: ImageView img = (ImageView) findViewById(R.id.action_infolinks_splash) it's for to get the width&height image programmatically. Yesterday i improve the code to rescale and i use only xxhdpi jpg image (1026px x 770px), like that i make smaller app and the image adjust for all screen size sucessfuly.
-
jmtsilva69 over 8 yearsIn xml: <***.****.TouchImageView android:id="@+id/action_infolinks_about_support" android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@mipmap/myinfolinks_about_support" android:scaleType="centerInside" android:contentDescription="@string/aboutSupport_description_image"/>
-
Skizo-ozᴉʞS over 8 yearsBut does it zoom in zoom out repeatly? I mean with 1 click it zooms in zooms out repeatly
-
Skizo-ozᴉʞS over 8 yearsI want when click an ImageView it zooms in and zooms out infinity with your answer can I do it?
-
alexbirkett about 8 yearsNo need to use
setOnTouchListener()
you can just overridepublic boolean onTouchEvent(MotionEvent event)
-
alexbirkett about 8 yearsThere are some issues with this: * The initial zoom is wrong (Possible solution use
scale = Math.min(scaleX, scaleY);
inadjustScale()
. * The zooming does not follow the mid point between fingers -
roroinpho21 about 8 yearsGreat job. I modified a bit your code. I disabled the ability to move the image on X or Y if the width or height is less then display's bounds
-
Umair almost 8 years@ChiragRaval can we use it on the layout ? which contains multiples images ... I am trying to zoom and swipe left, right, up, down but couldn't find a way to accomplish it.
-
Yohanim over 7 yearsFollow our community guidelines . Do not provide external links because links in the future may not be accessible. Furthermore, give some snippet code.
-
Dr.jacky over 7 years@ChiragRaval How to use this class for a imageView inserted in XML?
-
Shubham A. over 7 yearsWe can actually zoom out the original image to make it smaller. How to prevent this? Image should not go less than 100% of its original size.
-
roroinpho21 over 7 years@ROHITPARMAR I will post a new comment with my class.
-
user2630165 over 7 yearsWorking great. How can I get the real image x,y coordinates when a click was performed?
-
Admin over 7 yearsPerfect class! One question, how can I log the X/Y-position on action up relative to the ImageView's X/Y-position. Now it registers all the white space around it... I want to know the coordinates inside my ImageView.
-
Alejandro Cumpa almost 7 yearsI have been using this for a while, but now I wanted to use it with Glide and it won't show the image, then I updated the reference to android.support.v7.widget.AppCompatImageView and get it works.
-
Alejandro Cumpa almost 7 yearsIf this doesn't work try extending android.support.v7.widget.AppCompatImageView.
-
Daniel Viglione almost 7 yearsThis is exactly what I want but for a bitmap in canvas for scaling
-
temirbek almost 7 yearshow to make it zoom in with double tap when in original size?
-
Vishwajit Palankar over 6 yearsis there a way to restore the scaling of image when the
ImageView
is double tapped? -
Leonid Ustenko over 6 yearsKinda ugly to do all this stuff within an Activity
-
Muhammad Noman over 6 yearsHi, Can you tell me how to use that in Main Class? I came up with this, Can you tell me what should be the next? ZoomableImageView touch =(ZoomableImageView)findViewById(R.id.image1);
-
CoolMind over 6 yearsStrange, but after replacing
ImageView
in XML withiImage
, I got "android.view.InflateException: Binary XML file line #0: Error inflating class ...iImage". -
CoolMind over 6 yearsThanks! Works nice. If you use this widget inside
ViewPager
, some difficulties appear. 1) A scale is not reset to 1 after moving forward and backward. 2) If you try to shift a picture, the movement is slow and short. And you can occasionally move to next picture. It's not a problem of the solution, but you should realize a new behaviour. -
CoolMind over 6 yearsDoesn't work when image is inside ViewPager. Shows empty screen. While similar solutions and derived projects work
-
Zia Ur Rahman about 6 yearsGood, but this is only for imageview. How to attach a Class extended by View to this attacher. Have you any idea,
-
Däñish Shärmà about 6 yearsyour example have incomplete code, so many errors and ImageViewTouch class missing.
-
Beeing Jk almost 6 yearsnot so smooth when put it in a ScrollView with multiple images
-
Wesos de Queso almost 6 yearsIm actually amazed by this. Works great inside my fragment.
-
Mehdi Dehghani almost 6 yearsHow to avoid to much zoom out?
-
Mehdi Dehghani almost 6 yearsYou added
getWidth()
andgetHeight()
inonScale
method, where is the implementation of them? -
MohammedAli over 5 yearshow can i zoom outside of viewpager means a whole screen?
-
Feuby over 5 yearsThis works very well. I trid other answers and they did not work, or did not work properly.
-
Lensflare over 5 yearsI am using your class in a kotlin project. All I had to do is to replace the ImageView with your ZoomableImageView in the layout xml and it did work out of the box! Thanks.
-
Sanal S over 5 yearsI can't seem to apply this on an ImageView added to WindowManager in a class extending Service class.
-
Ed J almost 5 yearsThis is an outdated version. See the repo for instructions for latest PhotoView: github.com/chrisbanes/PhotoView
-
appukrb over 4 years@Chirag could you update the code, when click on first tap moved to the top of the screen
-
arniotaki over 4 yearsAlthough the PhotoView according to above links instructions it does not work. Your answer (PhotoViewAttacher) seems to work
-
Asad Ali over 4 yearsThis code is working fine, its purpose is to ZoomIn/ZoomOut a view not the image in it.
-
SuppressWarnings about 4 yearsI start it with setImageURI(imageUri) and every image appears black... The view does get the correct size, height and different attributes but doesnt display anything no matter the image.
-
Zain about 4 years@SuppressWarnings thanks for notifying that, I am not sure if I tried to set it programmatically; need to look back.. and will mention you for any workaround :)
-
mr.volatile almost 3 yearsUsing this code image is zoom in/out infinitely, how to restrict it?
-
Asesha George over 2 yearsexcellent solution, nice approach. Thank You
-
mikeB about 2 yearsThis is a great sample. Thanks to Chirag and @Nikunj Paradva. I have two things that I want to add in my code, One, limit the min and max zoom size, and Two, have the click (touch) event to be handled (like navigate back). I will work at this but if anyone has a suggestion...