使用 Matrix 的随触摸旋转的ImageView
突然想做个 类似 旋转开关的东西。然后就用了surfaceView做了个一个。
快做完的时候 朋友说道可以使用imageView来实现我想要的效果,然后就研究了下。
几个keypoint点
1.需要设置setScaleType(ScaleType.MATRIX);
2.matrix 需要new出来 通过getImageMatrix()的不行
3.通过setImageMatrix() 会调用invalidate() 从而重绘。
另外:
Matrix的
postRotate与setRotate
postRotate会基于Matrix上次的矩阵旋转
而setRotate会重置矩阵然后旋转
注:可延伸至Matrix 的postXX setXX
普通旋转:
iv 为imageView对象。
Matrix m=new Matrix();
m.postRotate(30f,iv.getWidth()/2,iv.getHeight()/2);
iv.setImageMatrix(m);
代码如下:
package com.lurencun.poolotools.ui.light; import android.content.Context; import android.graphics.Canvas; import android.graphics.Matrix; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.ImageView; /** * 随触摸旋转ImageView * * @author liupoolo * @since 2013-02-22 * @version 1.00 */ public class TouchRoateImageView extends ImageView { private final static float MIN_DEGREE = 0f; private final static float MAX_DEGREE = 360f; private Matrix m; private float saveX; // 当前保存的x private float saveY; // 当前保存的y private float curTouchX; // 当前触屏的x private float curTouchY; // 当前触摸的y private float centerX; // 中心点x private float centerY; // 中心点y private float curDegree; // 当前角度 private float changeDegree; public TouchRoateImageView(Context context, AttributeSet attrs) { super(context, attrs); setScaleType(ScaleType.MATRIX);// 重点 m = new Matrix(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); centerX = this.getWidth() / 2; centerY = this.getHeight() / 2; } public boolean onTouchEvent(MotionEvent event) { handleTouch(event); return true; } private void handleTouch(MotionEvent event) { curTouchX = event.getX(); curTouchY = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: saveTouchPoint(); break; case MotionEvent.ACTION_MOVE: handleTouchMove(); break; case MotionEvent.ACTION_UP: // 可以使用访问者模式这里让访问者获得当前角度 break; } } private void handleTouchMove() { changeDegree = (float) getActionDegrees(centerX, centerY, saveX, saveY, curTouchX, curTouchY); float tempDegree = (float) curDegree + changeDegree; if (tempDegree >= MIN_DEGREE && tempDegree <= MAX_DEGREE) { optimize(tempDegree);//优化变动 m.setRotate(curDegree, centerX, centerY); setImageMatrix(m);// 此方法会 调用invalidate() 从而重绘界面 } saveTouchPoint(); } private void optimize(float tempDegree){ if(tempDegree>MAX_DEGREE-1){ curDegree=MAX_DEGREE; }else if(tempDegree<MIN_DEGREE+1){ curDegree=MIN_DEGREE; }else{ this.curDegree = tempDegree; } } private void saveTouchPoint() { saveX = curTouchX; saveY = curTouchY; } /** * 获取两点到第三点的夹角。 * * @param x * @param y * @param x1 * @param y1 * @param x2 * @param y2 * @return */ private double getActionDegrees(float x, float y, float x1, float y1, float x2, float y2) { double a = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); double b = Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); double c = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y)); // 余弦定理 double cosA = (b * b + c * c - a * a) / (2 * b * c); // 返回余弦值为指定数字的角度,Math函数为我们提供的方法 double arcA = Math.acos(cosA); double degree = arcA * 180 / Math.PI; // 接下来我们要讨论正负值的关系了,也就是求出是顺时针还是逆时针。 // 第1、2象限 if (y1 < y && y2 < y) { if (x1 < x && x2 > x) {// 由2象限向1象限滑动 return degree; } // 由1象限向2象限滑动 else if (x1 >= x && x2 <= x) { return -degree; } } // 第3、4象限 if (y1 > y && y2 > y) { // 由3象限向4象限滑动 if (x1 < x && x2 > x) { return -degree; } // 由4象限向3象限滑动 else if (x1 > x && x2 < x) { return degree; } } // 第2、3象限 if (x1 < x && x2 < x) { // 由2象限向3象限滑动 if (y1 < y && y2 > y) { return -degree; } // 由3象限向2象限滑动 else if (y1 > y && y2 < y) { return degree; } } // 第1、4象限 if (x1 > x && x2 > x) { // 由4向1滑动 if (y1 > y && y2 < y) { return -degree; } // 由1向4滑动 else if (y1 < y && y2 > y) { return degree; } } // 在特定的象限内 float tanB = (y1 - y) / (x1 - x); float tanC = (y2 - y) / (x2 - x); if ((x1 > x && y1 > y && x2 > x && y2 > y && tanB > tanC)// 第一象限 || (x1 > x && y1 < y && x2 > x && y2 < y && tanB > tanC)// 第四象限 || (x1 < x && y1 < y && x2 < x && y2 < y && tanB > tanC)// 第三象限 || (x1 < x && y1 > y && x2 < x && y2 > y && tanB > tanC))// 第二象限 return -degree; return degree; } public float getCurDegree() { return curDegree; } public void setCurDegree(float curDegree) { if (curDegree >= MIN_DEGREE && curDegree <= MAX_DEGREE) { this.curDegree = curDegree; m.setRotate(curDegree, centerX, centerY); setImageMatrix(m); } } }