可缩放的ImageView

来源:互联网 发布:小河淌水 知乎 编辑:程序博客网 时间:2024/04/30 07:43

本博客为 http://www.imooc.com/learn/239 的笔记

/** *  *  首先在  onGlobalLayout() 中将图片缩放居中 *  然后在缩放手势中 对图片进行缩放,并进行边界的检测 *  然后 在touchEnvent中对图片进行平移 *  然后 在手势中 对双击事件进行处理,实现对图片的缩放 *  最后,对父控件的事件拦截进行条件的判断并且处理 *  */public class ZoomImageView extends ImageView implements                               OnGlobalLayoutListener, OnTouchListener,                                   OnScaleGestureListener {    private Context ctx;    // 对图片操作的类    private Matrix scaleMatrix;    //测量标志位,避免多次的测量造成的误差    private boolean isOnce;    //最初的缩放比例    private float initScale=0;    //双击之后的缩放比例    private float MidScale=0;    //最大的缩放比例    private float MaxScale=0;    //-----------------------------------------------------------------    //缩放手势    private ScaleGestureDetector scaleGestureDetector;    //-----------------------------------------------------------------    // 图片的平移    //上一次的多指触控的数目    private int mLastPointCount;    ///上一次中心点的坐标    private float mLastCenterX;    private float mLastCenterY;    //移动的临界点    private float mTouchSlop;    //------------------------------------------------------------------    //操作手势    private GestureDetector detector;    //是否在缩放    private boolean isAuto;    public ZoomImageView(Context context, AttributeSet attrs) {        this(context, attrs, 0);        this.ctx = context;        scaleMatrix = new Matrix();        mTouchSlop=ViewConfiguration.get(context).getTouchSlop();        scaleGestureDetector=new ScaleGestureDetector(ctx, this);        //处理双击事件        detector=new GestureDetector(ctx, new GestureDetector.SimpleOnGestureListener(){            @Override            public boolean onDoubleTap(MotionEvent e) {                if(!isAuto){                    //获取当前的缩放值                    float scale=getScale();                    float x=e.getX();                    float y=e.getY();                    if(scale <MidScale){                       postDelayed(new AutoScaleRunnable(MidScale, x, y), 16);                       isAuto=true;                    }else{                       postDelayed(new AutoScaleRunnable(initScale, x, y), 16);                       isAuto=true;                    }                }                return super.onDoubleTap(e);            }        });        setOnTouchListener(this);        super.setScaleType(ScaleType.MATRIX);    }    public ZoomImageView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    public ZoomImageView(Context context) {        this(context, null);    }    /**     * 实现缓慢的缩放     */    class AutoScaleRunnable implements Runnable {        private float targetScale;        private float centerX;        private float centerY;        // 临时的缩放比例        private float tempScale;        /**         *          * @param targetScale 目标的缩放比例         * @param centerX 缩放的中心         * @param centerY 缩放的中心         */        public AutoScaleRunnable(float targetScale, float centerX, float centerY) {            this.targetScale = targetScale;            this.centerX = centerX;            this.centerY = centerY;            float curScale = getScale();            if (curScale < targetScale) {                // /放大                tempScale = 1.07f;            } else {                // 缩小                tempScale = 0.93f;            }        }        @Override        public void run() {            scaleMatrix.postScale(tempScale, tempScale, centerX, centerY);            checkBorderAndCenter();            setImageMatrix(scaleMatrix);            float curScale = getScale();            if ((tempScale < 1.0f && curScale > targetScale)                    || (tempScale > 1.0f && curScale < targetScale)) {                // 继续执行线程                postDelayed(this, 16);            } else {                float scale = targetScale / curScale;                scaleMatrix.postScale(scale, scale, centerX, centerY);                checkBorderAndCenter();                setImageMatrix(scaleMatrix);                isAuto = false;            }        }    };    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        getViewTreeObserver().addOnGlobalLayoutListener(this);    }    @SuppressLint("NewApi")    @Override    protected void onDetachedFromWindow() {        super.onDetachedFromWindow();        getViewTreeObserver().removeOnGlobalLayoutListener(this);    }    @Override    public void onGlobalLayout() {        if (!isOnce) {            Drawable d=getDrawable();            if(d==null){                return ;            }            //获取控件的宽高            int width=getWidth();            int height=getHeight();            //获取图片的宽高            int dw=d.getIntrinsicWidth();            int dh=d.getIntrinsicHeight();            //图片缩放比例            float scale=0;              if(dw >width && dh >height){                scale=Math.min((width*1.0f/dw),(height*1.0f/dh));            }            if(dw<width && dh <height){                scale=Math.min((width*1.0f/dw), (height*1.0f/dh));            }            if(dw >width && dh <height){                scale=width*1.0f/dw;                }            if(dw <width && dh >height){                scale=height*1.0f/dh;            }            initScale=scale;            MidScale=initScale*2;            MaxScale=initScale*4;            float offX=getWidth()/2-dw/2;            float offY=getHeight()/2-dh/2;            //先平移,然后缩放            scaleMatrix.postTranslate(offX, offY);            //缩放的中心为控件的中心            scaleMatrix.postScale(scale, scale, getWidth()/2, getHeight()/2);            setImageMatrix(scaleMatrix);            isOnce = true;        }    }    /**     * 获取当前图片的缩放比例     * @return     */    public float getScale(){        float[] values=new float[9];        scaleMatrix.getValues(values);        return values[Matrix.MSCALE_X];    }    @Override    public boolean onTouch(View arg0, MotionEvent arg1) {        if(detector.onTouchEvent(arg1)){            return true;        }        scaleGestureDetector.onTouchEvent(arg1);        int pCount=arg1.getPointerCount();        //中心点的坐标        float centerX=0;        float centerY=0;        for(int i=0;i<pCount;i++){            centerX+=arg1.getX(i);            centerY+=arg1.getY();        }        centerX/=pCount;        centerY/=pCount;        if(mLastPointCount!=pCount){              mLastCenterX=centerX;              mLastCenterY=centerY;        }        mLastPointCount=pCount;        float dx=centerX-mLastCenterX;        float dy=centerY-mLastCenterY;        switch(arg1.getAction()){        case MotionEvent.ACTION_DOWN:            RectF rectf1=getMatrixRectF();             if(rectf1.width() >getWidth()  ||  rectf1.height() >getHeight()){                 //请求父控件不要拦截事件                 this.getParent().requestDisallowInterceptTouchEvent(true);             }            break;        case MotionEvent.ACTION_MOVE:            RectF rectf2=getMatrixRectF();             if(rectf2.width() >getWidth()  ||  rectf2.height() >getHeight()){                 this.getParent().requestDisallowInterceptTouchEvent(true);             }            if(Math.sqrt((dx*dx+dy*dy))>mTouchSlop){                RectF rectf=getMatrixRectF();                if(rectf.width() <getWidth()){                    dx=0;                }                if(rectf.height()<getHeight()){                    dy=0;                }                //平移                scaleMatrix.postTranslate(dx, dy);                checkBorderAndCenter();                setImageMatrix(scaleMatrix);            }            break;        case MotionEvent.ACTION_UP:             mLastPointCount=0;            break;        }        return true;    }    @Override    public boolean onScale(ScaleGestureDetector arg0) {        //缩放的因子        float factor=arg0.getScaleFactor();        //获取当前图片的缩放比例        float scale=getScale();        if((factor<1.0f && scale >initScale)                ||(factor >1.0f && scale <MaxScale)){            if(scale *factor >MaxScale){                factor=MaxScale*1.0f/scale;            }            if(scale *factor <initScale){                factor=initScale*1.0f/scale;            }            scaleMatrix.postScale(factor, factor, arg0.getFocusX(), arg0.getFocusY());            checkBorderAndCenter();            setImageMatrix(scaleMatrix);        }        return false;    }    /**     * 获取图片的宽高与四点坐标的值     * @return     */    public RectF getMatrixRectF(){        RectF rectf=new RectF();        Drawable d=getDrawable();        Matrix matrix=scaleMatrix;        if(d!=null){            rectf.set(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight());            matrix.mapRect(rectf);            return rectf;        }        return  rectf;    }    /**     * 在缩放的过程中进行边界与中心的检测     */    private void checkBorderAndCenter() {        int height=getHeight();        int width=getWidth();        float dx=0;        float dy=0;        RectF rectf=getMatrixRectF();        if(rectf.width() >=getWidth()){            if(rectf.left>0){                dx=-rectf.left;            }            if(rectf.right<width){                dx=width-rectf.right;            }        }        if(rectf.height() >=getHeight()){            if(rectf.top >0){                dy=-rectf.top;            }            if(rectf.bottom <height){                dy=height-rectf.bottom;            }        }        // 当图片的宽小于控件的宽度        if (rectf.width() < getWidth()) {            dx = getWidth() / 2 - rectf.right + rectf.width() / 2;        }        // 当图片的高度小于控件的高度        if (rectf.height() < getHeight()) {            dy = getHeight() / 2 - rectf.bottom + rectf.height() / 2;        }        scaleMatrix.postTranslate(dx, dy);    }    @Override    public boolean onScaleBegin(ScaleGestureDetector arg0) {        return true;    }    @Override    public void onScaleEnd(ScaleGestureDetector arg0) {    }}
0 0
原创粉丝点击