I have succeeded to zoom imageView by this site idea:
the problem that appears to me now is: i use an next and previous buttons to load images in the same image view when that done the new image loaded zoomed in. i need to view it in normal size and let user to zoom it if he want.
import android.annotation.SuppressLint;
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.view.View;
import android.widget.ImageView;
@SuppressLint("AppCompatCustomView")
public class MyTouchImageView extends ImageView {
// We can be in one of these 3 states
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int CLICK = 3;
private static final int ZOOM = 2;
private float origWidth, origHeight;
private Matrix matrix;
private int mode = NONE;
private PointF last = new PointF();
private PointF start = new PointF();
private float minScale = 1f;
private float maxScale = 3f;
private float[] m;
private int viewWidth, viewHeight;
private float saveScale = 1f;
private int oldMeasuredWidth, oldMeasuredHeight;
private ScaleGestureDetector mScaleDetector;
private Context context;
public MyTouchImageView(Context context) {
super(context);
sharedConstructing(context);
}
public MyTouchImageView(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);
setMinimumHeight(800);
setMinimumWidth(1000);
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
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
}
});
}
public void setMaxZoom(float x) {
maxScale = x;
}
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;
Drawable drawable = getDrawable();
if (drawable == null || drawable.getIntrinsicWidth() == 0
|| drawable.getIntrinsicHeight() == 0)
return;
int bmWidth = drawable.getIntrinsicWidth();
int bmHeight = drawable.getIntrinsicHeight();
float scaleX = (float) viewWidth / (float) bmWidth;
float scaleY = (float) viewHeight / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
// Center the image
float redundantYSpace = (float) viewHeight
- (scale * (float) bmHeight);
float redundantXSpace = (float) viewWidth
- (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = viewWidth - 2 * redundantXSpace;
origHeight = viewHeight - 2 * redundantYSpace;
setImageMatrix(matrix);
}
fixTrans();
}
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;
}
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;
}
}
}
LOADING IMAGE
private MyTouchImageView Title_images;
Title_images = findViewById(R.id.title_image);
Glide.with(Objects.requireNonNull(StudentInsideExam.this)).load(examInsideDatas.get(ShownPointIndexInArray).getImageUrls()).into(Title_images);
XML:
<FrameLayout
android:id="@+id/container1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<com.ayman.learningway.MyTouchImageView
android:id="@+id/title_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginTop="@dimen/smallMargin"
android:background="@color/tan_background"
android:scaleType="matrix"
android:visibility="gone" />
</LinearLayout>
</FrameLayout>
In order to avoid using the same scale of the previous image when you navigate to the next image, you need to reset the previous image to its original scale.
If you notice when you first load your image into your MyTouchImageView
, it loads with its original scale which is normally (1f), you can find that in the MyTouchImageView
with the statement private float saveScale = 1f;
Also when you pinch zoom your image, then onScale()
of the ScaleGestureDetector.SimpleOnScaleGestureListener
within the MyTouchImageView
is triggered.
So what you need to do to reset the image to its original scale is to reverse the last operation happened within onScale()
. Which is normally allows you to back to a scale of 1f.
To to that add the below method to your MyTouchImageView
:
public void resetToOriginalScale() {
// reverse the operation happened on onScale() method
float scaleFactor = (float) 1.0 / saveScale;
// reset the scale to the original scale
saveScale = 1f;
matrix.postScale(scaleFactor, scaleFactor, viewWidth / 2, viewHeight / 2);
fixTrans();
// Simulating a touch event within the ImageView in order to allow it to redraw with the original scale
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis() + 100;
int metaState = 0;
MotionEvent motionEvent = MotionEvent.obtain(
downTime,
eventTime,
MotionEvent.ACTION_UP,
0,
0,
metaState
);
dispatchTouchEvent(motionEvent);
}
Then whenever you navigate to a new image, you first need to reset the scale of the current image by calling resetToOriginalScale()
:
mImageView = findViewById(R.id.title_image);
mImageView.resetToOriginalScale();
Glide.with(MainActivity.this).load(new_image_url).centerCrop().into(mImageView);
Use .centerCrop()
with all your Glide invocations.
Hope this solves your problem.