美文网首页
Android ScaleGestureDetector实现可缩

Android ScaleGestureDetector实现可缩

作者: Mundy | 来源:发表于2019-04-23 22:03 被阅读0次

    今天我们来做一个可以根据手势进行缩放的图片查看器。
    首先是需要用到的几个东西:
    1.Matrix (用来实现图片的缩放)
    Matrix可以实现对图形进行平移,缩放,旋转等操作。在这里,我们主要用到的是平移和缩放。
    postTranslate(dx,dy) 对图形进行平移
    postScale(sx,sy,px,py)对图形进行缩放
    2.ScaleGestureDetector (对缩放手势的监听)

    ScaleGestureDetector gestureDetector=new ScaleGestureDetector(mContext, new ScaleGestureDetector.OnScaleGestureListener() {
                @Override
                public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
    
                    float factor=scaleGestureDetector.getScaleFactor();//缩放因子,这个是根据两个手指来计算缩放的倍数
    
    
                    return true;
                }
    
                @Override
                public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
                    //缩放开始,这里返回true表示要接收这个事件,必须为true,onScale才能执行
                    return true;
                }
    
                @Override
                public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
    
                    //缩放结束
                 
                }
            });
    

    以上就是实现本文功能的两个重点了。下面我们就开始写代码了
    首先要先写一个view继承Imageview

    public class PhotoView extends AppCompatImageView {
    
        private Context mContext;
    
        public PhotoView(Context context) {
            super(context);
            //在代码中new PhotoView()的时候会调用这个初始化
    
            mContext=context;
            init();
        }
    
        public PhotoView(Context context, AttributeSet attrs) {
            super(context, attrs);
            //在布局中使用会调用这个初始化
            mContext=context;
            init();
        }
    
        void init(){
            //初始化
    
            
        }
    }
    

    这样,自定义photoview的主结构就出来了。接下来就是对图形的处理了。
    我们无法保证所加载的图片的宽高,所以我们第一步需要对图片进行放大或缩小。使图片适应view的大小,并将图片移动到屏幕中间。下面是代码实现

    public class PhotoView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener {
    //这里我们需要实现 ViewTreeObserver.OnGlobalLayoutListener,这个接口用于测量大小
    
    ...省略构造函数
    
    void init(){
          mMatrix=new Matrix();//初始化
          setScaleType(ScaleType.MATRIX);//设置类型,使图片能支持Matrix
    
    }
    @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
          //需要在这里添加监听。
            getViewTreeObserver().addOnGlobalLayoutListener(this);
        }
    }
    

    下面是实现

    @Override
        public void onGlobalLayout() {
            if(isFristLoad){
                //因为onGlobalLayout可能会回调多次,所以这里要加个布尔值,控制下面的代码只执行一次,这里也可以改成把监听移除。
                isFristLoad=false;
    
                int width=getWidth();//获取view的宽度
                int height=getHeight();//获取view的高度
                Drawable drawable=getDrawable();//获取加载的图片
                if(drawable==null){
                    return;
                }
                int imgWidth=drawable.getIntrinsicWidth();//获取图片的宽度
                int imgHeight=drawable.getIntrinsicHeight();//获取图片的宽度
    
          
                //下面是计算出图片的大小和view大小相差的倍数,然后对图片进行缩放,
                if(imgWidth>width||imgHeight>height){
                    //当图片比view大的,需要缩小
                    //图片宽或高超过view
                    if(imgWidth>imgHeight){
                        //乘1f是为了不让scale变成int值
                        //mScale是一个全局的变量,存放初始的缩放倍数
                        mScale=width*1f/imgWidth*1f;
                    }else {
                        mScale=height*1f/imgHeight*1f;
                    }
    
                }else if(imgWidth<width&&imgHeight<height) {
                    //当图片比view小,需要放大
                    //图片宽高都小于view
                    if(imgWidth>imgHeight){
                        mScale=width*1f/imgWidth*1f;
                    }else {
                        mScale=height*1f/imgHeight*1f;
                    }
                }
    
              
                //这个方法文章开头有介绍过,设置移动到view中间
                mMatrix.postTranslate(width/2-imgWidth/2,height/2-imgHeight/2);
                //根据前面计算出的倍数,对图片进行缩放,使图片适应view大小
                mMatrix.postScale(mScale,mScale,width/2,height/2);
    
                //将修改应用到图片上。
                setImageMatrix(mMatrix);
    
    
            }
        }
    

    接下来就是对手势的监听了,上面我们已经说过ScaleGestureDetector得基础实现,下面我们就用它来实现手势缩放.

    void init(){
    
            mMatrix=new Matrix();
            setScaleType(ScaleType.MATRIX);
    
    
            gestureDetector=new ScaleGestureDetector(mContext, new ScaleGestureDetector.OnScaleGestureListener() {
                @Override
                public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
    
               
                    float factor=scaleGestureDetector.getScaleFactor();//缩放因子
                    float scale=getScale();//获取Matrix当前的缩放数值
                    
                    if(scale*factor>MAX_SCALE||scale*factor<=mScale*0.8){
                        //MAX_SCALE是一个全局变量,为了防止图片放大太大,我们设置一个值,图片放大到这个值就不能再放大。
                        //后面那个0.8的作用我们在下面的onScaleBegin里面做说明
                      
                    }else {
                      //根据手指获取缩放中心,然后根据缩放因子进行缩放
                        //原理和我们上面的一样
                      mMatrix.postScale(factor,factor,scaleGestureDetector.getFocusX(),scaleGestureDetector.getFocusY());
    
                        setImageMatrix(mMatrix);
                    }
                    return true;
                }
    
                @Override
                public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
                    return true;
                }
    
                @Override
                public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
                    //这里是缩放结束后做的操作,
                  //上面onScale那个0.8就是配合下面这段代码的
                  //下面是获取当前缩放值,mScale就是我们第一步里面图片适应了view时候的倍数
                  //上面的0.8是我们允许在缩放过程中,图片缩小到原来80%的大小
                  //然后再缩放结束后,回复到100%的大小。这样一来,图片就会又一个回弹的效果(参考微信)
                    float scale=getScale();//获取当前缩放值
                    if(scale<mScale){
                        //恢复到100%大小
                        float s=mScale/scale;
                        mMatrix.postScale(s,s,getWidth()/2,getHeight()/2);
                        setImageMatrix(mMatrix);
                    }
    
    
                }
            });
    
    
    
    
        }
    
    //需要在onTouchEvent里面改成调用gestureDetector.onTouchEvent(event);
    @Override
        public boolean onTouchEvent(MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
        }
    
    

    这样,我们就实现了一个手势缩放的图片查看器。下面是完整代码

    public class PhotoView 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 PhotoView(Context context) {
            super(context);
            mContext=context;
            init();
        }
    
        public PhotoView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mContext=context;
            init();
        }
    
    
        void init(){
    
            mMatrix=new Matrix();
            setScaleType(ScaleType.MATRIX);
            gestureDetector=new ScaleGestureDetector(mContext, new ScaleGestureDetector.OnScaleGestureListener() {
                @Override
                public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
    
                  
                    float factor=scaleGestureDetector.getScaleFactor();
                    float scale=getScale();
    
                    if(scale*factor>MAX_SCALE||scale*factor<=mScale*0.8){
    
                    }else {
    
                        mMatrix.postScale(factor,factor,getWidth()/2,getHeight()/2);
    
                        setImageMatrix(mMatrix);
                    }
                    return true;
                }
    
                @Override
                public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
                    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);
        }
    
    
        //获取当前缩放值
        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();
                Drawable drawable=getDrawable();
                if(drawable==null){
                    return;
                }
                int imgWidth=drawable.getIntrinsicWidth();
                int imgHeight=drawable.getIntrinsicHeight();
    
    
    
                if(imgWidth>width||imgHeight>height){
                    //图片宽或高超过view
                    if(imgWidth>imgHeight){
                        //乘1f是为了不让scale变成int值
                        mScale=width*1f/imgWidth*1f;
                    }else {
                        mScale=height*1f/imgHeight*1f;
                    }
    
                }else if(imgWidth<width&&imgHeight<height) {
                    //图片宽高都小于view
                    if(imgWidth>imgHeight){
                        mScale=width*1f/imgWidth*1f;
                    }else {
                        mScale=height*1f/imgHeight*1f;
                    }
                }
    
        
                mMatrix.postTranslate(width/2-imgWidth/2,height/2-imgHeight/2);
                mMatrix.postScale(mScale,mScale,width/2,height/2);
    
    
                setImageMatrix(mMatrix);
    
    
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Android ScaleGestureDetector实现可缩

          本文链接:https://www.haomeiwen.com/subject/qoibgqtx.html