本文是在别人做的ImageView实现缩放,平移功能的基础上做了优化并加上了旋转功能.
一,缩放
缩放通过双击屏幕和双指移动实现.
1,双击缩放
通过GestureDetector获取双击事件

mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){@Overridepublic boolean onDoubleTap(MotionEvent e) {//如果此刻正在进行自动的缓慢缩放,则禁止用户双击缩放if (isAutoScale){return true;}float x = e.getX();float y = e.getY();if (getScale() < mMidScale) {postDelayed(new AutoScaleRunnable(mMidScale,x,y),16);}else {postDelayed(new AutoScaleRunnable(mInitScale,getWidth()/2,getHeight()/2),16);}isAutoScale = true;return true;}
双击后我们可以直接把图片缩放到指定的大小,但是为了提高用户体验,我们通过postDelayed(Runnable action, long delayMillis)实现过程缩放,我们看AutoScaleRunnable
//实现缓慢缩放private class AutoScaleRunnable implements Runnable{//缩放的目标比例private float mTargetScale;//缩放的中心点private float x;private float y;private final float BIGGER = 1.07f;private final float SMALLER = 0.93f;//临时缩放比例private float tempScale;public AutoScaleRunnable(float mTargetScale,float x,float y) {this.mTargetScale = mTargetScale;this.x = x;this.y = y;if (getScale() < mTargetScale) {tempScale = BIGGER;}if (getScale() > mTargetScale) {tempScale = SMALLER;}}@Overridepublic void run() {//进行缩放mMatrix.postScale(tempScale,tempScale,x,y);checkBorderAndCenterWhenScale();setImageMatrix(mMatrix);float currentScale = getScale();//如果可以放大或者缩小if ((tempScale > 1.0f && currentScale < mTargetScale) || (tempScale < 1.0f && currentScale > mTargetScale) ){postDelayed(this,16);}//设置为目标缩放比例else {float scale = mTargetScale / currentScale;mMatrix.postScale(scale,scale,x,y);checkBorderAndCenterWhenScale();setImageMatrix(mMatrix);isAutoScale = false;}}}

1,先根据getScale()和mTargetScale判断是缩小还是放大并得到tempScale.其中BIGGER和SMALLER是指每次缩放倍数.
2,然后每次缩放tempScale倍,判断currentScale和mTargetScale,如果还可以放大或缩小,则继续postDelayed(this,16);
3,直到放大中currentScale > mTargetScale或缩小中currentScale < mTargetScale。则设置为目标缩放比例进行最后一次缩放.
每次缩放都要进行边界以及位置的控制,参看checkBorderAndCenterWhenScale()

//在缩放的时候进行边界以及位置的控制private void checkBorderAndCenterWhenScale() {RectF rectf = getMatrixRectF();float deltaX = 0;float deltaY = 0;int width = getWidth();int height = getHeight();//缩放时进行边界检测,防止出现留白if (rectf.width() >= width) {if (rectf.left > 0) {deltaX = -rectf.left;}if (rectf.right < width) {deltaX = width - rectf.right;}}if (rectf.height() >= height) {if (rectf.top > 0) {deltaY = -rectf.top;}if (rectf.bottom < height) {deltaY = height - rectf.bottom;}}//如果宽度或者高度小于控件的宽度或高度,则让其居中if (rectf.width() < width) {deltaX = width / 2f - rectf.right + rectf.width() / 2f;}if (rectf.height() < height) {deltaY = height / 2f - rectf.bottom + rectf.height() / 2f;}mMatrix.postTranslate(deltaX,deltaY);}

2,手指多点触控缩放
通过ScaleGestureDetector实现

mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {            @Override            public boolean onScale(ScaleGestureDetector detector) {                //获取当前图片的缩放比例                float scale = getScale();                //多点触控缩放比例                float scaleFactor = detector.getScaleFactor();                if (getDrawable() == null){                    return true;                }                //进行缩放范围的控制                if ((scale < mMaxScale && scaleFactor > 1.0f) || (scale > mInitScale && scaleFactor < 1.0f)) {                    if (scale * scaleFactor < mInitScale) {                        scaleFactor = mInitScale / scale;                    }if (scale * scaleFactor > mMaxScale) {                        scaleFactor = mMaxScale / scale;                    }                    //缩放                    mMatrix.postScale(scaleFactor,scaleFactor,detector.getFocusX(),detector.getFocusY());                    //在缩放的时候进行边界以及位置的控制                    checkBorderAndCenterWhenScale();                    setImageMatrix(mMatrix);                }                return true;            }            @Override            public boolean onScaleBegin(ScaleGestureDetector detector) {                return true;            }            @Override            public void onScaleEnd(ScaleGestureDetector detector) {            }        });

onScale中获取当前图片的缩放比例scale和多点触控缩放比例scaleFactor,进行缩放范围的控制后做缩放处理.
3,平移
平移要在onTouchEvent中,由于手势的优先级高,所以把mGestureDetector.onTouchEvent(event)和mScaleGestureDetector.onTouchEvent(event);
放在前面,注释比较清楚,不做详解

@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mGestureDetector.onTouchEvent(event)) {return true;}mScaleGestureDetector.onTouchEvent(event);float x = 0;float y = 0;int pointerCount = event.getPointerCount();//累加x和y方向的距离for (int i = 0; i < pointerCount; i++){x += event.getX(i);y += event.getY(i);}//获得中心点位置x /= pointerCount;y /= pointerCount;if (mLastPointerCount != pointerCount) {isCanDrag = false;mLastX = x;mLastY = y;}mLastPointerCount = pointerCount;RectF rectF = getMatrixRectF();switch (event.getAction()){case MotionEvent.ACTION_DOWN:/** * 此View在ViewPager中使用时,图片放大后自由移动的事件会与 * ViewPager的左右切换的事件发生冲突,导致图片放大后如果左右 * 移动时不能自由移动图片,而是使ViewPager切换图片.这是由于事 * 件分发时外层的优先级比内层的高,使用下列判断可以解决 */if (rectF.width() > getWidth() || rectF.height() > getHeight()) {getParent().requestDisallowInterceptTouchEvent(true);}break;case MotionEvent.ACTION_MOVE:if (rectF.width() > getWidth() || rectF.height() > getHeight()) {getParent().requestDisallowInterceptTouchEvent(true);}//偏移量float dx = x - mLastX;float dy = y - mLastY;if (!isCanDrag){isCanDrag = isMoveAction(dx,dy);}if (isCanDrag) {if (getDrawable() != null) {isCheckLeftAndRight = true;isCheckTopAndBottom = true;//如果宽度小于控件的宽度,不允许横向移动if (rectF.width() < getWidth()) {isCheckLeftAndRight = false;dx = 0;}//如果高度小于控件的高度,不允许纵向移动if (rectF.height() < getHeight()) {isCheckTopAndBottom = false;dy = 0;}mMatrix.postTranslate(dx,dy);//当自由移动时进行边界检查,防止留白checkBorderWhenTranslate();setImageMatrix(mMatrix);}}mLastX = x;mLastY = y;break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:mLastPointerCount = 0;break;}return true;}

4,旋转
对mMatrix做postRotate操作即可.

public void rotate(int i) {mMatrix.postRotate(i,getWidth()/2,getHeight()/2);checkBorderAndCenterWhenScale();setImageMatrix(mMatrix);}

5,getScale()方法
这个方法在多个地方调用,就是获取当前的scale
这里需要注意的是获取scale时,我们是从矩阵中获取MSCALE_X或MSCALE_Y

但旋转了以后就不能获取MSCALE_X了,如下矩阵:
0.72 0.0 -3.0517578E-5
0.0 0.72 -36.48004
0.0 0.0 1.0
旋转90°后变成这样
0.0 -0.72 1500.48
0.72 0.0 383.99997
0.0 0.0 1.0
此时我们就需要获取MSKEW_X或MSKEW_Y并取其绝对值

//获取当前图片的缩放比例public float getScale(){float[] values = new float[9];mMatrix.getValues(values);return values[Matrix.MSCALE_X]==0?Math.abs(values[Matrix.MSKEW_X]):Math.abs(values[Matrix.MSCALE_X]);}

代码地址:http://download.csdn.net/download/bigboysunshine/10025059

更多相关文章

  1. Android(安卓)如何用HttpClient 以Get方式获取数据并添加http头
  2. android 缩放图片引起的内存溢出
  3. Android(安卓)Fragment与Fragment之间数据获取
  4. Android中的网络编程系列(一):URLConnection
  5. android ContentResolver的使用(获取和修改联系人信息demo)
  6. webview 设定和使用缓存来获取网页中的js,css和图片资源
  7. android的aidl进程间通讯(二)
  8. Android(安卓)获取手机信息实例详解
  9. Android即时通讯——融云——基本环境搭建(坑很多)

随机推荐

  1. Android的onMeasure和onLayout And Measu
  2. Android(安卓)4.0 SDK下载安装
  3. android appwidget 笔记
  4. Android:Apk插件出现Permission Denial: s
  5. 安装android apk包/adb shell的常见问题
  6. Message Looper Handler三者之间的关联
  7. 二种方法实现 Android(安卓)TabWidget
  8. APPS大乱斗:4大Android文件浏览器横评(七)
  9. Android(安卓)四大存储方式
  10. Android(安卓)Zygote源码分析