Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

打造自己的可双击放大、多指缩放、放大等功能的ImageView

$
0
0

不多说上代码

package com.sdp.panda.myviewapp.view;

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 80926 on 2016/11/23.
 */


public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,
        ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener {
    //多指的放大与缩小的成员变量
    private boolean mOnce;
    private float mInitScale;//初始化的最小缩放值
    private float mMidScale;//双击的缩放值
    private float mMaxScale;//放大的最大值
    private Matrix mMatrix;
    private ScaleGestureDetector mScaleGestureDetector;//手势

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~````
    //自由移动的成员变量
    private int mLastPointerCount;//最后多指的数目
    private float mLastX;
    private float mLastY;
    private int mTouchSlop;
    private boolean isCanDrag;//可以拖拽
    private boolean isMoveTopAndBottom;//是否可以上移下移
    private boolean isMoveLeftAndRight;

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``~~~~~~~~~~~~~~~~
    //双击的成员变量
    private GestureDetector mGestureDetector;//双击的类
    private boolean isAutoScale;//避免用户一直双击

    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

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

    public ZoomImageView(Context context) {
        this(context, null);//一个参数的引用两个参数的
    }

    private void init(Context context) {
        mMatrix = new Matrix();
//        setScaleType(ScaleType.MATRIX);
        mScaleGestureDetector = new ScaleGestureDetector(context, this);
        setOnTouchListener(this);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();//是可以move的值
        mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                if (isAutoScale){
                    return true;
                }
                float x = e.getX();
                float y = e.getY();
                if (getScale()<mMidScale){
//                    mMatrix.postScale(mMidScale/getScale(),mMidScale/getScale(),x,y);
//                    setImageMatrix(mMatrix);
                    postDelayed(new AutoScaleRunnable(mMidScale,x,y),15);
                    isAutoScale = true;
                }else {
//                    mMatrix.postScale(mInitScale/getScale(),mInitScale/getScale(),x,y);
//                    setImageMatrix(mMatrix);
                    postDelayed(new AutoScaleRunnable(mInitScale,x,y),15);
                    isAutoScale = true;
                }
                return true;
            }
        });
    }


    @Override
    public void onGlobalLayout() {
        if (!mOnce) {

            int width = getWidth();//控件的宽和高
            int height = getHeight();
            Drawable drawable = getDrawable();
            if (drawable == null) {
                return;
            }
            float scaleSize = 0;//缩放尺寸
            int dWidth = drawable.getIntrinsicWidth();//图片的宽和高
            int dHeight = drawable.getIntrinsicHeight();
            if (dWidth > width && dHeight < height) {
                scaleSize = width * 1.0f / dWidth;//防止为0,提前转换为float类型
            }
            if (dHeight > height && dWidth < width) {
                scaleSize = height * 1.0f / dHeight;
            }
            if (dWidth > width && dHeight > height || dWidth < width && dHeight < height) {
                scaleSize = Math.min(height * 1.0f / dHeight, width * 1.0f / dWidth);
            }
            mInitScale = scaleSize;
            mMidScale = mInitScale * 2;//双击的初始化的两倍
            mMaxScale = mInitScale * 4;//最大是初始化的4倍
            //将图片移动至屏幕的中心
            int centerX = (width - dWidth) / 2;
            int centerY = (height - dHeight) / 2;
            mMatrix.postTranslate(centerX, centerY);
            mMatrix.postScale(mInitScale, mInitScale, width / 2, height / 2);
            setImageMatrix(mMatrix);//矩阵 长度为9的一元数组
            mOnce = true;
        }
    }

    @Override
    protected void onAttachedToWindow() {//实现window的时候天剑
        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 onScale(ScaleGestureDetector detector) {//缩放中
        float scaleFactor = detector.getScaleFactor();//获取缩放值
        //缩放区间 initScale~maxScale;
        float scale = getScale();
        if (getDrawable() == null) {
            return true;
        }
        if (scale < mMaxScale && scaleFactor > 1.0f ||
                scale > mInitScale && scaleFactor < 1.0f) {
            if (scale * scaleFactor < mInitScale) {
                scaleFactor = mInitScale / scale;
            }
            if (scale * scaleFactor > mMaxScale) {
                scaleFactor = mMaxScale / scale;
            }
            mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
            setImageViewInCenterWhenCheck();
            setImageMatrix(mMatrix);
        }
        return true;
    }

    //获取可以得到图片的四个角的矩形
    private RectF getMatrixRectF() {
        Matrix mMatrix = this.mMatrix;
        RectF rectF = new RectF();
        Drawable d = getDrawable();
        if (d != null) {
            rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            mMatrix.mapRect(rectF);
        }
        return rectF;
    }

    //设置图片在缩放最后中间
    private void setImageViewInCenterWhenCheck() {
        RectF matrixRectF = getMatrixRectF();
        float postX = 0;
        float postY = 0;
        int width = getWidth();
        int height = getHeight();
        if (matrixRectF.width() >= width) {
            if (matrixRectF.left > 0) {
                postX = -matrixRectF.left;
            }
            if (matrixRectF.right < width) {
                postX = width - matrixRectF.right;
            }
        }
        if (matrixRectF.height() >= height) {
            if (matrixRectF.top > 0) {
                postY = -matrixRectF.top;
            }
            if (matrixRectF.bottom < height) {
                postY = height - matrixRectF.bottom;
            }
        }
        //宽度和高度小于控件的宽和高的时候让其居中
        if (matrixRectF.width() < width) {
            postX = width / 2 - matrixRectF.right + matrixRectF.width() / 2;
        }
        if (matrixRectF.height() < height) {
            postY = height / 2 - matrixRectF.bottom + matrixRectF.height() / 2;
        }
        mMatrix.postTranslate(postX, postY);
    }
    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {//开始
        return true;
    }
    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {}

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event)){
            return true;
        }
        mScaleGestureDetector.onTouchEvent(event);
        float x = 0;
        float y = 0;
        int pointerCount = event.getPointerCount();
        for (int i = 0; i < pointerCount; i++) {
            x += event.getX(i);
            y += event.getY(i);
        }
        x /= pointerCount;
        y /= pointerCount;
        if (mLastPointerCount != pointerCount) {
            isCanDrag = false;
            mLastX = x;
            mLastY = y;
        }
        mLastPointerCount = pointerCount;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //解决与viewPager的冲突事件:加上0.01防止误差
                if (getMatrixRectF().width()>getWidth()+0.01||getMatrixRectF().height()>getHeight()+0.01){
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (getMatrixRectF().width()>getWidth()+0.01||getMatrixRectF().height()>getHeight()+0.01){
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                float dx = x - mLastX;
                float dy = y - mLastY;//移动量
                if (!isCanDrag) {
                    isCanDrag = isCanTouchMove(dx, dy);
                }
                if (isCanDrag) {
                    RectF matrixRectF = getMatrixRectF();
                    if (getDrawable() != null) {
                        isMoveLeftAndRight = isMoveTopAndBottom = true;
                        if (matrixRectF.width() < getWidth()) {//如果图片的宽和高小于控件的宽和高不允许移动
                            isMoveLeftAndRight = false;
                            dx = 0;
                        }
                        if (matrixRectF.height() < getHeight()) {
                            isMoveTopAndBottom = false;
                            dy = 0;
                        }
                        mMatrix.postTranslate(dx, dy);
                        WhenMoveCheck();
                        setImageMatrix(mMatrix);
                    }
                }
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mLastPointerCount = 0;
                break;
        }
        return true;
    }
    //该方法是用于制约图片移动的时候不会留白
    private void WhenMoveCheck() {
        RectF matrixRectF = getMatrixRectF();
        float dx = 0;
        float dy = 0;
        int width = getWidth();
        int height = getHeight();
        if (matrixRectF.top>0&&isMoveTopAndBottom){
            dy = - matrixRectF.top;
        }
        if (matrixRectF.bottom<height&&isMoveTopAndBottom){
            dy = height-matrixRectF.bottom;
        }
        if (matrixRectF.left>0&&isMoveLeftAndRight){
            dx = -matrixRectF.left;
        }
        if (matrixRectF.right<width&& isMoveLeftAndRight){
            dx = width-matrixRectF.right;
        }
        mMatrix.postTranslate(dx,dy);
        setImageMatrix(mMatrix);
    }

    private boolean isCanTouchMove(float dx, float dy) {
        return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;
    }

    private class AutoScaleRunnable implements Runnable{
        private float mTargetScale;//缩放的目标值
        private float x;
        private float y;//中心点
        private final float BIGGER = 1.05F;
        private final float SMALL = 0.95F;
        private float tmpScale;
        public AutoScaleRunnable(float targetScale,float x,float y){
            this.mTargetScale = targetScale;
            this.x = x;
            this.y = y;
            if (getScale()<mTargetScale){
                tmpScale = BIGGER;
            }
            if (getScale()>mTargetScale){
                tmpScale = SMALL;
            }
        }
        @Override
        public void run() {
            mMatrix.postScale(tmpScale,tmpScale,x,y);
            setImageViewInCenterWhenCheck();
            setImageMatrix(mMatrix);
            float currentScale = getScale();
            if (tmpScale>1.0f&&currentScale <mTargetScale || tmpScale<1.0f && currentScale>mTargetScale){
                postDelayed(this,15);
            }else {//设置目标值
                float scale = mTargetScale/currentScale;
                mMatrix.postScale(scale,scale,x,y);
                setImageViewInCenterWhenCheck();
                setImageMatrix(mMatrix);
                isAutoScale = false;
            }
        }
    }
}

此自定义控件可以与viewPager等使用,但是需处理其冲突事件

因为在viewPager中如不处理就无法进行对放大的图片进行点击移动的效果。。。
上述代码中:
  if (getMatrixRectF().width()>getWidth()+0.01
  ||getMatrixRectF().height()>getHeight()+0.01){
                getParent().requestDisallowInterceptTouchEvent(true);
            }
 正是处理这个冲突事件,只是先处理ImageView的放大缩小事件,最后可以进行滑动
作者:songdongpanCSDN 发表于2016/11/30 22:19:13 原文链接
阅读:17 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>