import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ViewTreeObserver;
import androidx.appcompat.widget.AppCompatImageView;
public class ZoomImageView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener {
//最大缩放倍数
private static int MAX_SCALE = 5;
//默认缩放倍数,初始化后会根据图片大小改变这个值
private static float mScale = 1f;
private Context mContext;
//手势缩放监听器
private ScaleGestureDetector gestureDetector;
//缩放工具
private Matrix mMatrix;
//首次加载,避免onGlobalLayout多次执行
private boolean isFristLoad = true;
public ZoomImageView(Context context) {
super(context);
mContext = context;
init();
}
public ZoomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public void init() {
mMatrix = new Matrix();
//设置类型,使图片能支持Matrix
setScaleType(ScaleType.MATRIX);
gestureDetector = new ScaleGestureDetector(mContext, new ScaleGestureDetector.OnScaleGestureListener() {
/**
* 缩放进行中,返回值表示是否下次缩放需要重置,如果返回ture,那么scaleGestureDetector就会重置缩放事件,如果返回false,scaleGestureDetector会在之前的缩放上继续进行计算
*/
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
if (null == getDrawable() || mMatrix == null) {
return true;
}
//缩放因子,这个是根据两个手指来计算缩放的倍数
float factor = scaleGestureDetector.getScaleFactor();
float scale = getScale();
if ((scale < mScale * MAX_SCALE && factor > 1.0f) || (scale > mScale && factor < 1.0f)) {
if (scale * factor < mScale) {
factor = mScale / scale;
}
if (scale * factor > mScale * MAX_SCALE) {
factor = mScale * MAX_SCALE / scale;
}
//以屏幕中央位置进行缩放
mMatrix.postScale(factor, factor, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY());
borderAndCenterCheck();
setImageMatrix(mMatrix);
}
return true;
}
/**
* 缩放开始,返回值表示是否受理后续的缩放事件
*/
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
//缩放开始,这里返回true表示要接收这个事件,必须为true,onScale才能执行
return true;
}
/**
* 缩放结束
*/
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
float scale = getScale();
if (scale < mScale) {
float s = mScale / scale;
mMatrix.postScale(s, s, getWidth() / 2, getHeight() / 2);
setImageMatrix(mMatrix);
}
}
});
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
//获取当前缩放值
private float getScale() {
float[] values = new float[9];
mMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
@Override
public void onGlobalLayout() {
if (isFristLoad) {
isFristLoad = false;
//获取控件的宽度和高度
int width = getWidth();
int height = getHeight();
//获取到ImageView对应图片的宽度和高度
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
// 图片固有宽度
int imgWidth = drawable.getIntrinsicWidth();
// 图片固有高度
int imgHeight = drawable.getIntrinsicHeight();
//接下来对图片做初始的缩放处理,保证图片能看全
if (imgWidth >= width && imgHeight >= height) {
// 图片宽度和高度都大于控件(缩小)
mScale = Math.min(width * 1.0f / imgWidth, height * 1.0f / imgHeight);
} else if (imgWidth > width && imgHeight < height) {
// 图片宽度大于控件,高度小于控件(缩小)
mScale = width * 1.0f / imgWidth;
} else if (imgWidth < width && imgHeight > height) {
// 图片宽度小于控件,高度大于控件(缩小)
mScale = height * 1.0f / imgHeight;
} else {
// 图片宽度小于控件,高度小于控件(放大)
mScale = Math.min(width * 1.0f / imgWidth, height * 1.0f / imgHeight);
}
// 将图片移动到手机屏幕的中间位置
float distanceX = width / 2 - imgWidth / 2;
float distanceY = height / 2 - imgHeight / 2;
mMatrix.postTranslate(distanceX, distanceY);
mMatrix.postScale(mScale, mScale, width / 2, height / 2);
setImageMatrix(mMatrix);
}
}
/**
* 获得图片放大缩小以后的宽和高
*/
private RectF getMatrixRectF() {
RectF rectF = new RectF();
Drawable drawable = getDrawable();
if (drawable != null) {
rectF.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
mMatrix.mapRect(rectF);
}
return rectF;
}
/**
* 图片在缩放时进行边界控制
*/
private void borderAndCenterCheck() {
RectF rect = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;
int viewWidth = getWidth();
int viewHeight = getHeight();
// 缩放时进行边界检测,防止出现白边
if (rect.width() >= viewWidth) {
if (rect.left > 0) {
deltaX = -rect.left;
}
if (rect.right < viewWidth) {
deltaX = viewWidth - rect.right;
}
}
if (rect.height() >= viewHeight) {
if (rect.top > 0) {
deltaY = -rect.top;
}
if (rect.bottom < viewHeight) {
deltaY = viewHeight - rect.bottom;
}
}
// 如果宽度或者高度小于控件的宽或者高;则让其居中
if (rect.width() < viewWidth) {
deltaX = viewWidth / 2f - rect.right + rect.width() / 2f;
}
if (rect.height() < viewHeight) {
deltaY = viewHeight / 2f - rect.bottom + rect.height() / 2f;
}
mMatrix.postTranslate(deltaX, deltaY);
}
}
网友评论