自定义ZoomImageView

跟着hyman做的ZoomImageView,实现了双击放大,缩小,多指触碰放大缩小的功能;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

/**
 * Created by Administrator on 2016/5/12.
 */
public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener, ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener {
    private Boolean first = false;
    private float initScale;//初始化的缩放量
    private float maxScale;//最大缩放量
    private float midScale;//中间缩放量
    private Matrix matrix;
    private int lastTouchPointCount = 0;//上次屏幕触点数
    private float lastX;
    private float lastY;
    private int onTouchSlop;//开始移动的滑动距离
    private Boolean isCanDrag = false;//是否可以移动
    private Boolean isNeedCheckTopAndBottom;//是否需要考虑top和boottom出现白边
    private Boolean isNeedCheckLeftAndRight;//是否需要考虑left和right出现白边
    private GestureDetector gestureDetector;//手势监听


    private ScaleGestureDetector scaleGestureDetector;//缩放手势监听

    public ZoomImageView(Context context) {
        this(context, null);
    }

    public ZoomImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setScaleType(ScaleType.MATRIX);//设置缩放类型
        matrix = new Matrix();
        scaleGestureDetector = new ScaleGestureDetector(getContext(), this);
        setOnTouchListener(this);
        onTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();//获取系统的默认开始移动的滑动距离
        /**
         * 处理双击图片放大和缩小
         */
        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                float scale = getScale();
                float eventX = e.getX();
                float eventY = getY();
                if (scale < midScale) {
                    postDelayed(new AutoScaleRunnable(eventX, eventY, maxScale), 16);

                } else {
                    postDelayed(new AutoScaleRunnable(eventX, eventY, initScale), 16);

                }
                return true;
            }
        });

    }

    /**
     * 用线程来实现图片缓慢变大和缩小
     */
    public class AutoScaleRunnable implements Runnable {
        private float clickX;
        private float clickY;
        private float targetScale;
        private float scaleTo;
        private float scaleBig = 1.07f;
        private float scaleSmall = 0.93f;

        public AutoScaleRunnable(float clickX, float clickY, float targetScale) {
            this.clickX = clickX;
            this.clickY = clickY;
            this.targetScale = targetScale;
            if (getScale() < targetScale) {
                scaleTo = scaleBig;
            }
            if (getScale() > targetScale) {
                scaleTo = scaleSmall;
            }
        }

        @Override
        public void run() {
            matrix.postScale(scaleTo, scaleTo, clickX, clickY);
            setImageMatrix(matrix);
            checkBorderWhenScale();
            float currentScale = getScale();
            if ((currentScale < targetScale && scaleTo > 1.0f) || (currentScale > targetScale && scaleTo < 1.0f)) {
                postDelayed(this, 16);
            } else {
                matrix.postScale(targetScale / currentScale, targetScale / currentScale, clickX, clickY);
                setImageMatrix(matrix);
                checkBorderWhenScale();

            }

        }
    }

    /**
     * 注册 GlobalLayoutListener监听事件

     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    /**
     * 移除监听事件
     */
    @Override
    protected void onDetachedFromWindow() {

        super.onDetachedFromWindow();
        getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }

    /**
     * 把图片定位到屏幕中央,并进行初始化缩放适应屏幕
     */
    @Override
    public void onGlobalLayout() {
        if (!first) {
            int with = getWidth();
            int height = getHeight();
            Drawable drawable = getDrawable();
            if (drawable == null) return;
            int draWith = drawable.getIntrinsicWidth();
            int draHeight = drawable.getIntrinsicHeight();
            if (draWith > with && draHeight < height) {
                initScale = with * 1.0f / draWith;
            }
            if ((draWith > with && draHeight > height) || (draWith < with && draHeight < height)) {
                initScale = Math.min(with * 1.0f / draWith, height * 1.0f / draHeight);
            }
            if (draWith < with && draHeight > height) {
//                initScale = height * 1.0f / draHeight;
                initScale = getWidth() * 1.0f / draHeight;
            }
            maxScale = 4f * initScale;
            midScale = 2f * initScale;
            float dx = with / 2.0f - draWith / 2.0f;
            float dy = height / 2.0f - draHeight / 2.0f;
            matrix.postTranslate(dx, dy);
            matrix.postScale(initScale, initScale, with / 2.0f, height / 2.0f);
            this.setImageMatrix(matrix);
            first = true;
        }
    }

    /**
     * 获得缩放图片中图片的缩放值
     *
     * @return
     */
    public float getScale() {
        float values[] = new float[9];
        matrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }

    /**
     * 获的缩放中图片的边界信息;
     *
     * @return
     */
    private RectF getDrawableInfo() {
        Drawable drawable = getDrawable();
        if (drawable == null)
            return null;
        int draWith = drawable.getIntrinsicWidth();
        int draHeight = drawable.getIntrinsicHeight();
        RectF rectF = new RectF();
        rectF.set(0, 0, draWith, draHeight);
        matrix.mapRect(rectF);//why
        return rectF;


    }

    /**
     * 处理多触点缩放
     * @param detector
     * @return
     */

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float scale = getScale();
        float scaleFactor = detector.getScaleFactor();
        if (getDrawable() == null) return true;
        if ((scale < maxScale && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) {
            if (scale * scaleFactor > maxScale) {
                scaleFactor = maxScale / scale;
            }
            if (scale * scaleFactor < initScale) {
                scaleFactor = initScale / scale;
            }

            matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
            setImageMatrix(matrix);
            checkBorderWhenScale();
        }


        return true;//why
    }

    /**
     * 缩放中边缘控制,防止边缘出现白边
     */
    private void checkBorderWhenScale() {
        RectF draRectF = getDrawableInfo();
        if (draRectF == null) return;
        int with = getWidth();
        int height = getHeight();
        float dx = 0;
        float dy = 0;
        if (draRectF.width() >= with) {
            if (draRectF.left > 0) {
                dx = -draRectF.left;
            }
            if (draRectF.right < with) {
                dx = with - draRectF.right;
            }
        }
        if (draRectF.height() >= height) {
            if (draRectF.top > 0) {
                dy = -draRectF.top;
            }
            if (draRectF.bottom < height) {
                dy = height - draRectF.bottom;
            }

        }
        if (draRectF.height() < height) {
            dy = (height / 2.0f - draRectF.bottom + draRectF.height() / 2.0f);
        }
        if (draRectF.width() < with) {
            dx = (with / 2.0f - draRectF.right + draRectF.width() / 2.0f);
        }
        matrix.postTranslate(dx, dy);
        setImageMatrix(matrix);
    }


    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;//why
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {

    }

    /**
     * 处理touch事件
     * @param v
     * @param event
     * @return
     */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (gestureDetector.onTouchEvent(event))//传入touch事件给GestureDetector
            return true;
        scaleGestureDetector.onTouchEvent(event);//传入touch事件给scaleGestureDetector
        int touchPointCount = event.getPointerCount();
        float x = 0;
        float y = 0;
        for (int i = 0; i < touchPointCount; i++) {
            x += event.getX(i);
            y += event.getY(i);
        }
        float centerX = x / touchPointCount;
        float centerY = y / touchPointCount;
        if (lastTouchPointCount != touchPointCount) {
            isCanDrag = false;
            lastX = centerX;
            lastY = centerY;
        }
        lastTouchPointCount = touchPointCount;
        RectF rectF = getDrawableInfo();
        switch (event.getAction()) {
//            case MotionEvent.ACTION_DOWN:
//                if (rectF != null && (rectF.height() > getHeight() || rectF.width() > getWidth())) {
//                    getParent().requestDisallowInterceptTouchEvent(true);//阻止父布局(viewpager)拦截事件
//                }
//                break;
            case MotionEvent.ACTION_MOVE:
//
//                if (rectF != null && (rectF.height() > getHeight() || rectF.width() > getWidth())) {
//                    getParent().requestDisallowInterceptTouchEvent(true);
//                }
                float dx = centerX - lastX;
                float dy = centerY - lastY;
                if (!isCanDrag) {
                    isCanDrag = isMoveAction(dx, dy);
                }
                if (isCanDrag) {
                    isNeedCheckLeftAndRight = true;
                    isNeedCheckTopAndBottom = true;
                    RectF drawRecF = getDrawableInfo();
                    if (drawRecF != null) {
                        if (drawRecF.width() < getWidth()) {
                            isNeedCheckLeftAndRight = false;
                            dx = 0;
                        }
                        if (drawRecF.height() < getHeight()) {
                            dy = 0;
                            isNeedCheckTopAndBottom = false;
                        }
                        matrix.postTranslate(dx, dy);
                        setImageMatrix(matrix);
                        checkBorderWhenTraslate();

                    }
                }
                lastX = centerX;
                lastY = centerY;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                lastTouchPointCount = 0;
                break;
            default:
                break;
        }

        return true;
    }

    /**
     * 保证触点缩放后平移不出现白边
     */
    public void checkBorderWhenTraslate() {
        RectF rectF2 = getDrawableInfo();
        float dx = 0;
        float dy = 0;
        if (rectF2 == null) return;
        if (rectF2.right < getWidth() && isNeedCheckLeftAndRight) {
            dx = getWidth() - rectF2.right;
        }
        if (rectF2.left > 0 && isNeedCheckLeftAndRight) {
            dx = -rectF2.left;
        }
        if (rectF2.top > 0 && isNeedCheckTopAndBottom) {
            dy = -rectF2.top;
        }
        if (rectF2.bottom < getHeight() && isNeedCheckTopAndBottom) {
            dy = getHeight() - rectF2.bottom;
        }
        matrix.postTranslate(dx, dy);
        setImageMatrix(matrix);
    }

    /**
     * 判断是否可以移动
     *
     * @param dx
     * @param dy
     * @return
     */

    private boolean isMoveAction(float dx, float dy) {

        return Math.sqrt(dx * dx + dy * dy) > onTouchSlop;
    }
}


你可能感兴趣的:(imageview)