Android可平移缩放旋转的ImageView的实现
本文是在别人做的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
更多相关文章
- Android(安卓)如何用HttpClient 以Get方式获取数据并添加http头
- android 缩放图片引起的内存溢出
- Android(安卓)Fragment与Fragment之间数据获取
- Android中的网络编程系列(一):URLConnection
- android ContentResolver的使用(获取和修改联系人信息demo)
- webview 设定和使用缓存来获取网页中的js,css和图片资源
- android的aidl进程间通讯(二)
- Android(安卓)获取手机信息实例详解
- Android即时通讯——融云——基本环境搭建(坑很多)