美文网首页
【Android】实现一个手势可旋转/缩放/移动的ImageVi

【Android】实现一个手势可旋转/缩放/移动的ImageVi

作者: 鲨鲨指挥官 | 来源:发表于2022-04-01 00:08 被阅读0次

我们在项目里经常会用到需要使用ImageView的地方,这时候有些产品经理可能会提出需要让这个ImageView玩出花样旋起来,原来的那个只能显示图片的就不好使了,需要考虑去实现一个功能更强大的ImageView了。

一、 准备工作

由于我们要实现的是一个可自由变换的ImageView,那么首先要想到的是如何通过手势的方式对特定的操作进行区分,这里使用了Github中封装手势操作的组件库Almeros/android-gesture-detectors,其对移动、旋转和缩放都进行了很好的封装,可以帮助我们减少很多麻烦。

repositories {
        //添加jitpack仓库
        maven { url 'https://jitpack.io' }
}
implementation 'com.github.Almeros:android-gesture-detectors:v1.0.1'

二、实现旋转

效果

实现思路

  1. 声明RotateGestureDetector对象,初始化并设置监听器等;
  2. 为ImageView设置setOnTouchListener事件,在其回调中让RotateGestureDetector实例对象接手触摸事件;
  3. 在RotateGestureDetector的监听器回调中,获取对应的变化值,并设置给ImageView。

代码实例

public class DemoRotateImageView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener{
    //操作对象
    private Matrix mMatrix;
    //旋转手势监听器
    private RotateGestureDetector mRotateGestureDetector ;
    //当前焦点
    private float mFocusX, mFocusY;

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

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

    public DemoRotateImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //记住,一定要把ScaleType设置成ScaleType.MATRIX,否则无法缩放
        setScaleType(ScaleType.MATRIX);
        mMatrix = new Matrix();
        //手势旋转
        mRotateGestureDetector = new RotateGestureDetector(context, new RotateGestureDetector.OnRotateGestureListener() {
            @Override
            public boolean onRotate(RotateGestureDetector detector) {
                float rotationDegrees = -detector.getRotationDegreesDelta();
                mMatrix.postRotate(rotationDegrees,mFocusX,mFocusY);
                setImageMatrix(mMatrix);
                return true;
            }

            @Override
            public boolean onRotateBegin(RotateGestureDetector detector) {
                return true;
            }

            @Override
            public void onRotateEnd(RotateGestureDetector detector) {

            }
        });
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mRotateGestureDetector.onTouchEvent(event);
        return true ;
    }
    public boolean mIsOneLoad = true;
    @Override
    public void onGlobalLayout() {
        if (mIsOneLoad) {
            //获取图片,如果没有图片则直接退出
            Drawable d = getDrawable();
            if (d == null){
                return;
            }
            //获取图片的宽和高
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();
            //将其中图片中心点作为焦点
            mFocusX = dw * 1.0f / 2 ;
            mFocusY = dh * 1.0f / 2 ;
            mIsOneLoad = false;
        }
    }
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        //修改窗口事件中对视图变化进行监听
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }
}

三、实现缩放

实现思路

  1. 声明ScaleGestureDetector对象,初始化并设置监听器等;
  2. 为ImageView设置setOnTouchListener事件,在其回调中让ScaleGestureDetector实例对象接手触摸事件;
  3. 在onGlobalLayout中设置初始、最大、最小缩放值;
  4. 在ScaleGestureDetector的监听器回调中,获取焦点并对缩放进行处理后设置ImageView;
  5. 当缩放值大于最大和最小缩放值后不允许其继续缩放。

代码实例

public class DemoScaleImageView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener{
    //操作对象
    private Matrix mMatrix;
    //缩放手势监听器
    private ScaleGestureDetector mScaleGestureDetector ;
    //图片宽高
    private float mFocusX, mFocusY;
    //初始化的比例,也就是最小比例
    private float mInitScale;
    //图片最大比例
    private float mMaxScale;
    //图片最小比例
    private float mMinScale ;

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

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

    public DemoScaleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //记住,一定要把ScaleType设置成ScaleType.MATRIX,否则无法缩放
        setScaleType(ScaleType.MATRIX);
        mMatrix = new Matrix();
        //手势旋转
        mScaleGestureDetector = new ScaleGestureDetector(context,new ScaleGestureDetector.SimpleOnScaleGestureListener(){
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                //开始缩放
                float scaleFactor = detector.getScaleFactor();
                Log.i("缩放操作值",scaleFactor+"");
                float scale = getCurrentScale();
                //缩放操作需要在mMinScale和mMaxScale中进行 范围外的话就拦截
                if(scale < mMaxScale && scale > mMinScale){
                    mMatrix.postScale(scaleFactor, scaleFactor, mFocusX, mFocusY);
                    setImageMatrix(mMatrix);
                    return true;
                }else{
                    return false;
                }
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                //开始缩放并获取焦点
                mFocusX = detector.getFocusX();
                mFocusY = detector.getFocusY();
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                super.onScaleEnd(detector);
            }
        });
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mScaleGestureDetector.onTouchEvent(event);
        return true ;
    }
    public boolean mIsOneLoad = true;
    @Override
    public void onGlobalLayout() {
        if (mIsOneLoad) {
            //获取图片,如果没有图片则直接退出
            Drawable d = getDrawable();
            if (d == null){
                return;
            }
            //获取图片的宽和高
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();
            //使其图片中点作为焦点
            mFocusX = dw * 1.0f / 2 ;
            mFocusY = dh * 1.0f / 2 ;
            //初始化缩放比例
            mInitScale = getCurrentScale();
            //手势放大时最大比例
            mMaxScale = mInitScale * 2;
            //手势缩小时的最小比例
            mMinScale = mInitScale * 0.8f ;
            mIsOneLoad = false;
        }
    }
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    /**
     * 获取当前图片的缩放值
     * @return 缩放值
     */
    private float getCurrentScale() {
        float[] values = new float[9];
        mMatrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }
}

相关文章

网友评论

      本文标题:【Android】实现一个手势可旋转/缩放/移动的ImageVi

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