美文网首页
支持放大缩小的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