美文网首页
支持放大缩小的ImageView

支持放大缩小的ImageView

作者: 旅行者归来 | 来源:发表于2019-11-30 11:45 被阅读0次
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);
    }
}

相关文章

网友评论

      本文标题:支持放大缩小的ImageView

      本文链接:https://www.haomeiwen.com/subject/euhowctx.html