通过手势缩放、移动ImageView的图片

先放上一张效果图:


在这里,我对自己的笔记本全屏截图,然后当作自定义ImageView的

Src放在真机上运行。

可以看到这里的图片是可以移动和缩放的。

在这里先说清一点,如果在xml的控件上设置src,则需要在代码上

通过getDrawable();获取,如果是通过setBackGround的,则通过

getBackground();获取即可。

public class MyImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, 
        View.OnTouchListener {
这个是我自定义ImageView的类名。

我在这里实现了一些待会会用到的接口。



    /**
     * 控件宽度
     */
    private int mWidth;
    /**
     * 控件高度
     */
    private int mHeight;
    /**
     * 拿到src的图片
     */
    private Drawable mDrawable;
    /**
     * 图片宽度(使用前判断mDrawable是否null)
     */
    private int mDrawableWidth;
    /**
     * 图片高度(使用前判断mDrawable是否null)
     */
    private int mDrawableHeight;

    /**
     * 初始化缩放值
     */
    private float mScale;

    /**
     * 双击图片的缩放值
     */
    private float mDoubleClickScale;

    /**
     * 最大的缩放值
     */
    private float mMaxScale;

    /**
     * 最小的缩放值
     */
    private float mMinScale;
    
    private ScaleGestureDetector scaleGestureDetector;
    /**
     * 当前有着缩放值、平移值的矩阵。
     */
    private Matrix matrix;

这些是我定义出来的一些成员变量,每个变量我都写上了作用。


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

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

    public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOnTouchListener(this);
        scaleGestureDetector = new ScaleGestureDetector(context, this);
        initListener();
    }

这里是三个标准的构造器,直接用短的引用长的就是了。

先看一看initListener();干了什么事情。


    /**
     * 初始化事件监听
     */
    private void initListener() {
        // 强制设置模式
        setScaleType(ScaleType.MATRIX);
        // 添加观察者
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 移除观察者
                getViewTreeObserver().removeOnGlobalLayoutListener(this);
                // 获取控件大小
                mWidth = getWidth();
                mHeight = getHeight();

                //通过getDrawable获得Src的图片
                mDrawable = getDrawable();
                if (mDrawable == null)
                    return;
                mDrawableWidth = mDrawable.getIntrinsicWidth();
                mDrawableHeight = mDrawable.getIntrinsicHeight();
                initImageViewSize();
                moveToCenter();
            }
        });
    }

这里唯一要注意的是我在初始化监听这个方法内,强制了ImageView的scaleType

模式为:MATRIX,因为等会会用到矩阵来缩放和平移,因此强制一下它的scaleT-

ype。


initImageViewSize();这个方法,光看名字就知道要初始化图片大小,来看一看怎么

样去初始化的。


/**
     * 初始化资源图片宽高
     */
    private void initImageViewSize() {
        if (mDrawable == null)
            return;

        // 缩放值
        float scale = 1.0f;
        // 图片宽度大于控件宽度,图片高度小于控件高度
        if (mDrawableWidth > mWidth && mDrawableHeight < mHeight)
            scale = mWidth * 1.0f / mDrawableWidth;
            // 图片高度度大于控件宽高,图片宽度小于控件宽度
        else if (mDrawableHeight > mHeight && mDrawableWidth < mWidth)
            scale = mHeight * 1.0f / mDrawableHeight;
            // 图片宽度大于控件宽度,图片高度大于控件高度
        else if (mDrawableHeight > mHeight && mDrawableWidth > mWidth)
            scale = Math.min(mHeight * 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
            // 图片宽度小于控件宽度,图片高度小于控件高度
        else if (mDrawableHeight < mHeight && mDrawableWidth < mWidth)
            scale = Math.min(mHeight * 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
        mScale = scale;
        mMaxScale = mScale * 8.0f;
        mMinScale = mScale * 0.5f;
    }

先判断一下有没有src资源,没有的话,这个方法调用也没意义了。

这里是要图片的宽或高其中一边充满着屏幕,在最后的三句话,意思就是,

首先,我们假设初始化缩放后的图片面积是A,允许它的最大放大倍数为8A,

最小缩小倍数为0.5A,就是这个意思,(是基于初始化缩放后的面积,而不是

原图的面积,想想这是笔记本的屏幕面积,很大吧!


moveToCenter();这个方法之前,先看一下不调用这个方法的效果图会咋样


scaleType为MATRIX属性的图片都是不经过缩放直接显示在屏幕左上角,

这时候肯定会有童鞋问,咦,刚刚不是缩放过么,我这时候只能说,孩子,

你太天真了,那只是理论上的缩放值,还没经过实操呢(滑稽)大笑


好吧,接下来就看看moveToCenter();做了什么事情,

    /**
     * 移动控件中间位置
     */
    private void moveToCenter() {
        final float dx = mWidth / 2 - mDrawableWidth / 2;
        final float dy = mHeight / 2 - mDrawableHeight / 2;
        matrix = new Matrix();
        // 平移至中心
        matrix.postTranslate(dx, dy);
        // 以控件中心作为缩放
        matrix.postScale(mScale, mScale, mWidth / 2, mHeight / 2);
        setImageMatrix(matrix);
    }
看注释的意思是要把它(图片)移动到屏幕的正中心,

dx的意思是取横方向上,控件中心到图片中心的值,如果大于0就向右移动,

反之向左移动相应的绝对值。

dy则换成纵向方向就是了。

在这里实例化了matrix对象(初始化一次就行),至于为什么只需要初始化一次,

因为图片的缩放值和平移值,都是通过matrix保存的,如果再一次初始化,缩放值

和平移值等等数据都会被清空。

我是先让它平时到控件正中心,然后以控件中心缩放mScale,mScale在initImageViewSize();的时候已经赋值了。

至于先缩放后平移,应该也是可以得,但可能计算公式相对麻烦些,

在这里本着方便为主的原则,就不再作计算了。

接下来会说到这个东西scaleGestureDetector = new ScaleGestureDetector(context, this);

通过这个方法,实现了监听事件,是手势滑动的监听事件。

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        
        return true;
    }


    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        
    }
但是,虽然实现了监听,但是然并卵,因为onTouch事件中没有它(scaleGestureDetector),在这里 ,重写onTouchEvent是没用的,因为onTouchEventListener的优先级比 onTouchEvent要高,所以我们只能这样子。

setOnTouchListener(this);
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        
        return scaleGestureDetector.onTouchEvent(event);
    }
在最后调用了scaleGestureDetector.onTouchEvent(event);这个方法。

然后手势生效了(呵呵哒得意)。

@Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }
这个方法是手势执行前生效,必须return ture, 不然onScale必定失效

现在重点说一下onScale,因为这个方法是处理手势的缩放,

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        if (mDrawable == null) {
            return true;
        }
        // 系统定义的缩放值
        float scaleFactor = detector.getScaleFactor();
        // 获取已经缩放的值
        float scale = getmScale();
        float scaleResult = scale * scaleFactor;
        if (scaleResult >= mMaxScale && scaleFactor > 1.0f)
            scaleFactor = mMaxScale / scale;
        if (scaleResult <= mMinScale && scaleFactor < 1.0f) 
            scaleFactor = mMinScale / scale;
        

        matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());

        /。。。
<span style="white-space:pre">	setImageMatrix(matrix);</span>
    }
其中,scaleFactor是获得手势缩放的值(具体怎么获取的不知道),当值>1.0f时,说明两个手指的滑动距离是不断增加(相对于两个手指都down了的那一瞬间),同理<1.0f说明两个手指的滑动距离不断减少,也是相对于那一瞬间,

    /**
     * @return 当前缩放的值
     */
    private float getmScale() {
        float[] floats = new float[9];
        matrix.getValues(floats);
        return floats[Matrix.MSCALE_X];
    }
通过这个方法 ,拿到了之前matrix对象的scaleX值( X和Y都没所谓,因为在这里都是一个值),然后将当前的scale*手势滑动的缩放值,得到最新的缩放值scaleResult,在这里做了一个最大放大值和最小缩小值得处理,如果 scaleResult大于等于最大缩放值和手指滑动为放大手势,则让手势缩放为一个恒定的最大放大值(反之同理)。


看效果图后,会觉得比较奇葩,因为缩小的时候,位置好像偏了!(原本是在控件正中心)。



    /**
     * @param matrix 矩阵
     * @return matrix的 l t b r 和width,height
     */
    private RectF getRectf(Matrix matrix) {
        RectF f = new RectF();
        if (mDrawable == null)
            return null;
        f.set(0, 0, mDrawableWidth, mDrawableHeight);
        matrix.mapRect(f);
        return f;
    }
首先看一下这个方法,通过这个方法,可以得到矩阵matrix的N维属性,并把这N维属性赋值到一个float类型的矩形上。


在将上面的/。。。补上

<span style="white-space:pre">	</span>RectF f = getRectf(matrix);
        float dX = 0.0f;
        float dY = 0.0f;
        // 图片高度大于控件高度
        if (f.height() >= mHeight) {
            // 图片顶部出现空白
            if (f.top > 0) {
                // 往上移动
                dY = -f.top;
            }
            // 图片底部出现空白
            if (f.bottom < mHeight) {
                // 往下移动
                dY = mHeight - f.bottom;
            }
        }
        // 图片宽度大于控件宽度
        if (f.width() >= mWidth) {
            // 图片左边出现空白
            if (f.left > 0) {
                // 往左边移动
                dX = -f.left;
            }
            // 图片右边出现空白
            if (f.right < mWidth) {
                // 往右边移动
                dX = mWidth - f.right;
            }
        }

        if (f.width() < mWidth) {
            dX = mWidth / 2 - f.right + f.width() / 2;
        }

        if (f.height() < mHeight) {
            dY = mHeight / 2 - f.bottom + f.height() / 2;
        }
        matrix.postTranslate(dX, dY);
        setImageMatrix(matrix);


首先获取矩阵matrix的N维并赋值在f身上。

在这里其实是细分为2种情况(横竖类似的合一)

以纵向为例:

// 图片高度大于控件高度
        if (f.height() >= mHeight) {
            // 图片顶部出现空白
            if (f.top > 0) {
                // 往上移动
                dY = -f.top;
            }
            // 图片底部出现空白
            if (f.bottom < mHeight) {
                // 往下移动
                dY = mHeight - f.bottom;
            }
        }

大概就是这个意思:当图片高度大于等于控件高度的时候,坚决不让控件高度方向上出现白色位置,此时,假设当图片和控件高度完全相同的时候,是不是图片的纵向刚好和控件完全重叠呢?

再看第二种情况:

        if (f.height() < mHeight) {
            dY = mHeight / 2 - f.bottom + f.height() / 2;
        }

之前说到,当图片和控件高度完全相同的时候,是不是图片的纵向刚好和控件完全重叠呢?其实,这句话不应该用假设句,而是肯定句,所以,想想,如果图片纵向恰好小于控件高度那么一点点,是不是图片纵向上瞬间就被移动到控件的中间呢?

这种情况的横向方向的道理完全一致,在此也说明一个道理,可以把复杂的事情细分了处理,反正方法是顺着执行的。

这样,图片的缩放就处理完了。


现在说一下移动图片

    private float downX;
    private float downY;
    private float nowMovingX;
    private float nowMovingY;
    private float lastMovedX;
    private float lastMovedY;
    private boolean isFirstMoved = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                isFirstMoved = false;
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                isFirstMoved = false;
                break;
            case MotionEvent.ACTION_MOVE:
                nowMovingX = event.getX();
                nowMovingY = event.getY();
                if (!isFirstMoved) {
                    isFirstMoved = true;
                    lastMovedX = nowMovingX;
                    lastMovedY = nowMovingY;
                }
                float dX = 0.0f;
                float dY = 0.0f;
                RectF rectf = getRectf(matrix);
                // 判断滑动方向
                final float scrollX = nowMovingX - lastMovedX;
                // 判断滑动方向
                final float scrollY = nowMovingY - lastMovedY;
                // 图片高度大于控件高度
                if (rectf.height() > mHeight && canSmoothY()) {
                    dY = nowMovingY - lastMovedY;
                }

                // 图片宽度大于控件宽度
                if (rectf.width() > mWidth && canSmoothX()) {
                    dX = nowMovingX - lastMovedX;
                }
                matrix.postTranslate(dX, dY);

                remedyXAndY(dX,dY);

                lastMovedX = nowMovingX;
                lastMovedY = nowMovingY;
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                isFirstMoved = false;
                break;
        }
        return scaleGestureDetector.onTouchEvent(event);
    }


MotionEvent.ACTION_POINTER_DOWN;这个也是压下的时候,区别在于只有不是第一根手指压下的时候才执行,

所以,我在压下的动作都初始化isFirstMoved=false;

当移动的时候,ACTION_MOVE也会执行。

由于移动的时候处理逻辑少的问题,出现屏幕越界后明显的白边反弹,因此在这里编辑了一部分代码。。。

滑动前,先判断能否滑动,滑动后,再次判断是否越界,因此,有效解决了白边反弹现象。

    /**
     * 判断x方向上能不能滑动
     * @return 可以滑动返回true
     */
    private boolean canSmoothX(){
        RectF rectf = getRectf(matrix);
        if (rectf.left >0 || rectf.right <getWidth())
            return false;
        return true;
    }

    /**
     * 判断y方向上可不可以滑动
     * @return 可以滑动返回true
     */
    private boolean canSmoothY(){
        RectF rectf = getRectf(matrix);
        if (rectf.top>0 || rectf.bottom < getHeight())
            return false;
        return true;
    }
以上是x和y方向上,滑动前判断可不可以滑动的片段代码。

    /**
     * 纠正出界的横和众线
     * @param dx 出界偏移的横线
     * @param dy 出街便宜的众线
     */
    private void remedyXAndY(float dx,float dy){
        if (!canSmoothX())
            matrix.postTranslate(-dx,0);
        if (!canSmoothY())
            matrix.postTranslate(0,-dy);
        setImageMatrix(matrix);
    }
这段是用于滑动之后判断是否越界的,如果越界,把多余的dx和dy滑动回去。



完整的自定义控件代码:

package com.test.gesturedemo.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.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

/**
 * Created by 13798 on 2016/6/3.
 */
public class MyImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener {
    /**
     * 控件宽度
     */
    private int mWidth;
    /**
     * 控件高度
     */
    private int mHeight;
    /**
     * 拿到src的图片
     */
    private Drawable mDrawable;
    /**
     * 图片宽度(使用前判断mDrawable是否null)
     */
    private int mDrawableWidth;
    /**
     * 图片高度(使用前判断mDrawable是否null)
     */
    private int mDrawableHeight;

    /**
     * 初始化缩放值
     */
    private float mScale;

    /**
     * 双击图片的缩放值
     */
    private float mDoubleClickScale;

    /**
     * 最大的缩放值
     */
    private float mMaxScale;

    /**
     * 最小的缩放值
     */
    private float mMinScale;

    private ScaleGestureDetector scaleGestureDetector;
    /**
     * 当前有着缩放值、平移值的矩阵。
     */
    private Matrix matrix;

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

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

    public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOnTouchListener(this);
        scaleGestureDetector = new ScaleGestureDetector(context, this);
        initListener();
    }


    /**
     * 初始化事件监听
     */
    private void initListener() {
        // 强制设置模式
        setScaleType(ScaleType.MATRIX);
        // 添加观察者
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 移除观察者
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
                // 获取控件大小
                mWidth = getWidth();
                mHeight = getHeight();

                //通过getDrawable获得Src的图片
                mDrawable = getDrawable();
                if (mDrawable == null)
                    return;
                mDrawableWidth = mDrawable.getIntrinsicWidth();
                mDrawableHeight = mDrawable.getIntrinsicHeight();
                initImageViewSize();
                moveToCenter();
            }
        });
    }

    /**
     * 初始化资源图片宽高
     */
    private void initImageViewSize() {
        if (mDrawable == null)
            return;

        // 缩放值
        float scale = 1.0f;
        // 图片宽度大于控件宽度,图片高度小于控件高度
        if (mDrawableWidth > mWidth && mDrawableHeight < mHeight)
            scale = mWidth * 1.0f / mDrawableWidth;
            // 图片高度度大于控件宽高,图片宽度小于控件宽度
        else if (mDrawableHeight > mHeight && mDrawableWidth < mWidth)
            scale = mHeight * 1.0f / mDrawableHeight;
            // 图片宽度大于控件宽度,图片高度大于控件高度
        else if (mDrawableHeight > mHeight && mDrawableWidth > mWidth)
            scale = Math.min(mHeight * 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
            // 图片宽度小于控件宽度,图片高度小于控件高度
        else if (mDrawableHeight < mHeight && mDrawableWidth < mWidth)
            scale = Math.min(mHeight * 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
        mScale = scale;
        mMaxScale = mScale * 8.0f;
        mMinScale = mScale * 0.5f;
    }

    /**
     * 移动控件中间位置
     */
    private void moveToCenter() {
        final float dx = mWidth / 2 - mDrawableWidth / 2;
        final float dy = mHeight / 2 - mDrawableHeight / 2;
        matrix = new Matrix();
        // 平移至中心
        matrix.postTranslate(dx, dy);
        // 以控件中心作为缩放
        matrix.postScale(mScale, mScale, mWidth / 2, mHeight / 2);
        setImageMatrix(matrix);
    }

    /**
     * @return 当前缩放的值
     */
    private float getmScale() {
        float[] floats = new float[9];
        matrix.getValues(floats);
        return floats[Matrix.MSCALE_X];
    }

    /**
     * @param matrix 矩阵
     * @return matrix的 l t b r 和width,height
     */
    private RectF getRectf(Matrix matrix) {
        RectF f = new RectF();
        if (mDrawable == null)
            return null;
        f.set(0, 0, mDrawableWidth, mDrawableHeight);
        matrix.mapRect(f);
        return f;
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        if (mDrawable == null) {
            return true;
        }
        // 系统定义的缩放值
        float scaleFactor = detector.getScaleFactor();
        // 获取已经缩放的值
        float scale = getmScale();
        float scaleResult = scale * scaleFactor;
        if (scaleResult >= mMaxScale && scaleFactor > 1.0f)
            scaleFactor = mMaxScale / scale;
        if (scaleResult <= mMinScale && scaleFactor < 1.0f)
            scaleFactor = mMinScale / scale;

        matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());

        RectF f = getRectf(matrix);
        float dX = 0.0f;
        float dY = 0.0f;
        // 图片高度大于控件高度
        if (f.height() >= mHeight) {
            // 图片顶部出现空白
            if (f.top > 0) {
                // 往上移动
                dY = -f.top;
            }
            // 图片底部出现空白
            if (f.bottom < mHeight) {
                // 往下移动
                dY = mHeight - f.bottom;
            }
        }
        // 图片宽度大于控件宽度
        if (f.width() >= mWidth) {
            // 图片左边出现空白
            if (f.left > 0) {
                // 往左边移动
                dX = -f.left;
            }
            // 图片右边出现空白
            if (f.right < mWidth) {
                // 往右边移动
                dX = mWidth - f.right;
            }
        }

        if (f.width() < mWidth) {
            dX = mWidth / 2 - f.right + f.width() / 2;
        }

        if (f.height() < mHeight) {
            dY = mHeight / 2 - f.bottom + f.height() / 2;
        }
        matrix.postTranslate(dX, dY);
        setImageMatrix(matrix);
        return true;
    }


    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        float scale = getmScale();
        if (scale < mScale) {
            matrix.postScale(mScale / scale, mScale / scale, mWidth / 2, mHeight / 2);
            setImageMatrix(matrix);
        }
    }


    private float downX;
    private float downY;
    private float nowMovingX;
    private float nowMovingY;
    private float lastMovedX;
    private float lastMovedY;
    private boolean isFirstMoved = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                isFirstMoved = false;
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                isFirstMoved = false;
                break;
            case MotionEvent.ACTION_MOVE:
                nowMovingX = event.getX();
                nowMovingY = event.getY();
                if (!isFirstMoved) {
                    isFirstMoved = true;
                    lastMovedX = nowMovingX;
                    lastMovedY = nowMovingY;
                }
                float dX = 0.0f;
                float dY = 0.0f;
                RectF rectf = getRectf(matrix);
                // 判断滑动方向
                final float scrollX = nowMovingX - lastMovedX;
                // 判断滑动方向
                final float scrollY = nowMovingY - lastMovedY;
                // 图片高度大于控件高度
                if (rectf.height() > mHeight && canSmoothY()) {
                    dY = nowMovingY - lastMovedY;
                }

                // 图片宽度大于控件宽度
                if (rectf.width() > mWidth && canSmoothX()) {
                    dX = nowMovingX - lastMovedX;
                }
                matrix.postTranslate(dX, dY);

                remedyXAndY(dX,dY);

                lastMovedX = nowMovingX;
                lastMovedY = nowMovingY;
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                isFirstMoved = false;
                break;
        }
        return scaleGestureDetector.onTouchEvent(event);
    }

    /**
     * 判断x方向上能不能滑动
     * @return 可以滑动返回true
     */
    private boolean canSmoothX(){
        RectF rectf = getRectf(matrix);
        if (rectf.left >0 || rectf.right <getWidth())
            return false;
        return true;
    }

    /**
     * 判断y方向上可不可以滑动
     * @return 可以滑动返回true
     */
    private boolean canSmoothY(){
        RectF rectf = getRectf(matrix);
        if (rectf.top>0 || rectf.bottom < getHeight())
            return false;
        return true;
    }

    /**
     * 纠正出界的横和众线
     * @param dx 出界偏移的横线
     * @param dy 出街便宜的众线
     */
    private void remedyXAndY(float dx,float dy){
        if (!canSmoothX())
            matrix.postTranslate(-dx,0);
        if (!canSmoothY())
            matrix.postTranslate(0,-dy);
        setImageMatrix(matrix);
    }
}


activity的xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.test.gesturedemo.view.MyImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="matrix"
        android:src="@mipmap/tt1"/>

</RelativeLayout>




  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值