`
119568242
  • 浏览: 420257 次
  • 性别: Icon_minigender_1
  • 来自: 深圳/湛江
社区版块
存档分类
最新评论

[android]使用 Matrix 的随触摸旋转的ImageView

 
阅读更多

使用 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);
		}

	}

}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics