学习篇---自定义ZoomImageView

来源:互联网 发布:oppo系统优化 编辑:程序博客网 时间:2024/06/03 01:42

跟着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;    }}


0 0
原创粉丝点击