探究ZoomImageVie中的图片居中和多点触控

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yoonerloop/article/details/87896776

 

ZoomImageView是一个支持收拾缩放,多点触控的开源控件,这篇文章学习他的图片居中和手势缩放。要缩放的是一个图片所以要用到自定义控件,我们MyZoomImageView,继承自AppCompatImageView实现他的构造方法,既然是图片的处理,我们这里用到了一个类Matrix,他是一个3×3的一个矩阵,可以对图片进行缩放、旋转、位移、倾斜等处理。因此需要在构造方法里面进行初始化,另外还需要获取到图片宽高信息,以及Drawable信息,这里实现OnGlobalLayoutListener接口,在onGlobalLayout方法中处理。如下:

    private void init(Context context) {
        setScaleType(ScaleType.MATRIX);
        mMatrix = new Matrix();
    }

在注册完OnGlobalLayoutListener接口后还需要进行注销,防止内存泄漏:

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

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

做好了上面的准备工作,现在我们先实现图片的居中显示,然后再实现多指触控缩放。

一、图片的居中显示

xml布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="header.footer.recycle.MainActivity">

        <header.footer.recycle.MyZoomImageView
            android:id="@+id/rl_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="matrix"
            android:background="#cccccc"
            android:src="@mipmap/ic_launcher"/>

    </RelativeLayout>

    实现思路:

  1. 获取图片宽高信息。
  2. 设置图片居中。
  3. 设置图片缩放。

由于获取图片信息只需要获取一次,因此需要在onGlobalLayout方法上面加个判断,防止图片缩放或者移动的时候多次调用,这里设置一个变量boolean,进行控制:

    @Override
    public void onGlobalLayout() {
        if (!flag) {
            //获取设置的宽高:一般为屏幕宽高
            mWidth = getWidth();
            mHeight = getHeight();
            //获取设置图片的尺寸
            Drawable drawable = getDrawable();
            if (drawable == null) {
                return;
            }
            mDrawableHeight = drawable.getIntrinsicHeight();
            mDrawableWidth = drawable.getIntrinsicWidth();
            //设置图片位置
            int dx = mWidth / 2 - mDrawableWidth / 2;
            int dy = mHeight / 2 - mDrawableHeight / 2;
            //平移
            mMatrix.postTranslate(dx, dy);
            //设置图片
            setImageMatrix(mMatrix);
            flag = true;
        }
    }

运行,如下图,很清楚的看到图片居中了。

这样上面一二步,就实现了,下面看第三步,设置图片缩放。首先得获取缩放系数,分为如下四种情况进行讨论,如下备注:

    private float getScaleSize() {
		float scale = 1.0f;
		//宽度很大,高度很小
		if (mDrawableWidth > mWidth && mDrawableHeight < mHeight) {
			scale = mWidth * 1.0f / mDrawableWidth;
		}
		//宽度很小,高度很大
		if (mDrawableWidth < mWidth && mDrawableHeight > mHeight) {
			scale = mHeight * 1.0f / mDrawableHeight;
		}
		//高度宽度都很大
		if (mDrawableWidth > mWidth && mDrawableHeight > mHeight) {
			float widthScale = mWidth * 1.0f / mDrawableWidth;
			float heightScale = mHeight * 1.0f / mDrawableHeight;
			//这里需要注意,为啥只min
			scale = Math.min(widthScale, heightScale);
		}
		//宽度很小,高度很小
		if (mDrawableWidth < mWidth && mDrawableHeight < mHeight) {
			float widthScale = mWidth * 1.0f / mDrawableWidth;
			float heightScale = mHeight * 1.0f / mDrawableHeight;
			//这里需要注意,为啥只min
			scale = Math.min(widthScale, heightScale);
		}
		return scale;
    }

获取到缩放系数之后还需要定义三个变量,分别是缩放初始值,缩放最小值,缩放最大值,,我们定义在成员变量,供后面使用:

        //设置缩放比
        private float minScale = 1.0f; //最小值为设置原图大小
        private float maxScale = minScale * 2.0f; //最大值为设置原图2倍大小
        private float madScale = minScale * 4.0f; //最最大值为设置原图4倍大小

再在onGlobalLayout中设置:

	@Override
	public void onGlobalLayout() {
		if (!flag) {
			//获取设置的宽高:一般为屏幕宽高
			mWidth = getWidth();
			mHeight = getHeight();
			//获取设置图片的尺寸
			Drawable drawable = getDrawable();
			if (drawable == null) {
				return;
			}
			mDrawableHeight = drawable.getIntrinsicHeight();
			mDrawableWidth = drawable.getIntrinsicWidth();
			//设置图片位置
			int dx = mWidth / 2 - mDrawableWidth / 2;
			int dy = mHeight / 2 - mDrawableHeight / 2;
			//缩放系数
			initScale = getScaleSize();
			mMatrix.postTranslate(dx, dy);
			//第一个、第二个为x,y周缩放比;后面两个为缩放中心,设置为屏幕中心为缩放中心
			mMatrix.postScale(initScale, initScale, mWidth / 2, mHeight / 2);
			//设置图片
			setImageMatrix(mMatrix);
			flag = true;
		}
	}

再次运行效果:

二、图片的多指触控缩放

多指触控需要用到ScaleGestureDetector这个类,该类主要是用于识别一些特定的手势,然后将事件交给TouchEvent方法,这样我们就不用额外处理手势事件了,只要要实现ScaleGestureDetector.OnScaleGestureListener,在回调中进行处理,然后再实现View.OnTouchListener接口,重写onTouch方法,把MotionEvent交个mGestureDetector。

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
    }

    OnScaleGestureListener回调方法一共有三个:

    //缩放中,返回true表示处理了
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        return false;
    }

    //缩放开始,一定要返回true,否则监听不到后面的回调
    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    //缩放结束
    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {

    }

手势的多点触控主要是在onScale方法里面进行处理:

@Override
    public boolean onScale(ScaleGestureDetector detector) {
        //获取当前的缩放事件
        float scaleFactor = detector.getScaleFactor();\
        //获取当前的缩放系数
        float currentScalse = getCurrentScaleSize();
        //判断是否设置图片
        if (getDrawable() == null) {
            return true;
        }
        // 用户将要放大图片或者用户将要缩小图片
        if ((scaleFactor > 1.0f && currentScalse < maxScale) ||
                (scaleFactor < 1.0f && currentScalse > minScale)) {
            // 缩小时
            if (scaleFactor * currentScalse < minScale) {
                scaleFactor = minScale / currentScalse;
            }
            // 放大时
            if (scaleFactor * currentScalse > maxScale) {
                scaleFactor = maxScale / currentScalse;
            }
            //执行缩放动作
            mMatrix.postScale(scaleFactor, scaleFactor, mWidth / 2, mHeight / 2);
            //设置mMatrix
            setImageMatrix(mMatrix);
        }
        //返回true,默认false
        return true;
    }

    /**
     * 当前缩放图片的缩放值:x,y缩放值一样,获取一个就可以
     *
     * @return
     */
    public float getCurrentScaleSize() {
        float[] values = new float[9];
        mMatrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }

 

就分析到这里,其他部分后面有时间了在接着分析!

 

 

 

猜你喜欢

转载自blog.csdn.net/yoonerloop/article/details/87896776