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.View;
import android.view.ViewTreeObserver;
import androidx.appcompat.widget.AppCompatImageView;
public class ZoomMoveImageView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener, View.OnTouchListener {
//最大缩放倍数-可以根据需求对外提供set方法
private static int MAX_SCALE = 10;
//默认缩放倍数,初始化后会根据图片大小改变这个值
private static float mScale = 1f;
private Context mContext;
//手势缩放监听器
private ScaleGestureDetector gestureDetector;
//缩放工具
private Matrix mMatrix;
//首次加载,避免onGlobalLayout多次执行
private boolean isFristLoad = true;
public ZoomMoveImageView(Context context) {
super(context);
mContext = context;
init();
}
public ZoomMoveImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public void init() {
mMatrix = new Matrix();
//设置类型,使图片能支持Matrix
setScaleType(ScaleType.MATRIX);
this.setOnTouchListener(this);
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);
}
private float preX, preY, currentX, currentY;
private int prePointerCount;
@Override
public boolean onTouch(View v, MotionEvent event) {
currentX = 0;
currentY = 0;
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
currentX += event.getX();
currentY += event.getY();
}
currentX /= pointerCount;
currentY /= pointerCount;
if (pointerCount != prePointerCount) {
preX = currentX;
preY = currentY;
prePointerCount = pointerCount;
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = currentX - preX;
float dy = currentY - preY;
setMovePosition(getDrawable(), mMatrix, dx, dy, getWidth(), getHeight());
setImageMatrix(mMatrix);
preX = currentX;
preY = currentY;
break;
case MotionEvent.ACTION_UP://有多根手指触摸屏幕时,只有当所有的手指抬起时这里才执行
prePointerCount = 0;
break;
}
return gestureDetector.onTouchEvent(event);
}
public static void setMovePosition(Drawable drawable, Matrix matrix, float dx, float dy, int w, int h) {
RectF rectF = new RectF(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
matrix.mapRect(rectF);
float rw = rectF.width();
float rh = rectF.height();
if (rw > w && rectF.left + dx <= 0 && rectF.right + dx >= w) {
matrix.postTranslate(dx, 0);
}
if (rh > h && rectF.top + dy <= 0 && rectF.bottom + dy >= h) {
matrix.postTranslate(0, dy);
}
}
public void setShowPosition(Drawable drawable, Matrix matrix, int w, int h) {
RectF rectF = new RectF(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
matrix.mapRect(rectF);
float rw = rectF.width();
float rh = rectF.height();
float moveX = 0, moveY = 0;
if (rw < w) {
moveX = w / 2 - rw / 2 - rectF.left;
}
if (rh < h) {
moveY = h / 2 - rh / 2 - rectF.top;
}
if (rw > w && rectF.left > 0) {
moveX = -rectF.left;
}
if (rw > w && rectF.right < w) {
moveX = w - rectF.right;
}
if (rh > h && rectF.top > 0) {
moveY = -rectF.top;
}
if (rh > h && rectF.bottom < h) {
moveY = h - rectF.bottom;
}
matrix.postTranslate(moveX, moveY);
}
}
网友评论