标签:android ontouchevent matirx
大风车系列版本1.0到版本3.0的体验有很大的不足:风车旋转的弧度都是手动写死的,不会根据手指移动的快慢而快慢。版本4.0将解决这个问题,思路如下:
1)以风车图片的中心为坐标原点简历一个直角坐标系,捕获手指按下事件也即是MotionEvent.ACTION_DOWN事件,记录此时手指的坐标点与直角坐标系x正坐标轴的夹角
2)获取手指移动的时候当前手指坐标点与直角坐标系x正轴的夹角。
3)计算步骤1和步骤2的两个夹角的差,就是手指此时移动的弧度。而不像版本3.0之前的那样写死了
具体代码设计如下:提供了速度控制器类SpeedControl类,在里面主要提供了获取当前坐标点与x正轴的夹角的方法,该类的的代码如下:
package rotation.demo.bean;
public class SpeedControl {
/** 手指按下时候的弧度 **/
private float down_rad;
/** 手指move时当前坐标的弧度 **/
private float current_move_rad;
/** 弧度增量,它的值等于current_move_rad - down_rad**/
private float Δrad;
/** 图片的中心原点 **/
private float x0, y0;
public SpeedControl(float x0, float y0) {
this.x0 = x0;
this.y0 = y0;
}
/***
* 计算当前坐标点与x轴的夹角所代表的弧度,弧度计算公式为 1rad = 180/Math.PI,<br>
* 需要注意的是直角坐标系分四个象限,每个象限的坐标点与x轴的夹角计算时需要计算一下
*
* @param current_x
* 当前坐标点的横坐标点
* @param current_y
* 当前坐标点的纵坐标点
* @return
*/
public float computeRad(float current_x, float current_y) {
final float Δx = current_x - x0;
final float Δy = current_y - y0;
double θ = 0f;// 夹角
// 求夹角的正切的绝对值
float tanθ = Math.abs(Δy / Δx);
if (Δx > 0) {// 当坐标点在1或者4象限的情况
if (Δy >= 0) {// 坐标点位于第一象限
θ = Math.atan(tanθ);
} else {// 当坐标点位于第四象限
θ = 2 * Math.PI - Math.atan(tanθ);
}
} else {// 当坐标点位于2或3象限
if (Δy >= 0) {// 位于第二象限
θ = Math.PI - Math.atan(tanθ);
} else {// 位于第三象限
θ = Math.PI + Math.atan(tanθ);
}
}
//注意一弧度 = 180/Math.PI
float result = (float) ((180 * θ) / Math.PI);
return result;
}
public float getDown_rad() {
return down_rad;
}
public void setDown_rad(float down_rad) {
this.down_rad = down_rad;
}
public float getCurrent_move_rad() {
return current_move_rad;
}
public void setCurrent_move_rad(float current_move_rad) {
this.current_move_rad = current_move_rad;
}
//该方法工Matrix.preRotate使用
public float getΔrad() {
return Δrad;
}
public void setΔrad(float δrad) {
Δrad = δrad;
}
}
package rotation.demo.view;
import rotation.demo.bean.SpeedControl;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* verson3.0 前两个版本都是手指离开屏幕的时候就会立即停止转动,现在这个版本让当手指抬起的时候,由于惯性让风车继续转动一点时间。
* 思路:监听手指抬起事件,然后重绘
*
* @author YanQiu
*
*/
public class RotationView extends View {
/** 要转动的图片 **/
private Bitmap bitMap;
/** 风车每次转动的弧度 **/
private int degree = 0;
/** 图片的宽度:在这里提供的是正方形的图片,所以宽度和高度是一样的 **/
private int width = 0;
/*** 图片的高度:在这里提供的是正方形的图片,所以宽度和高度是一样的 **/
private int height = 0;
/** 定义一个画笔 **/
private Paint paint = new Paint();
/**手指抬起的时间**/
private long upTime = 0;
/**手指抬起的时候风车持续转动的时间**/
private final long stopTimeDuration = 5000;
/**速度控制器**/
private SpeedControl speedControl;
public RotationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RotationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public RotationView(Context context) {
super(context);
}
private String tag = "";
/**
* 计算图片的圆心
*/
public void initSize() {
width = bitMap.getWidth();
height = bitMap.getHeight();
speedControl = new SpeedControl(width/2,height/2);
postInvalidate();
}
public void setBitMap(Bitmap bitMap) {
this.bitMap = bitMap;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(width, width);
}
@Override
protected void onDraw(Canvas canvas) {
Matrix matrix = new Matrix();
// 设置转轴位置
matrix.setTranslate((float) width / 2, (float) height / 2);
// 开始转,为手指转过的弧度
matrix.preRotate(speedControl.getΔrad());
// 转轴还原
matrix.preTranslate(-(float) width / 2, -(float) height / 2);
canvas.drawBitmap(bitMap, matrix, paint);
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN://获取手指按下的坐标点与x轴夹角的弧度
final float down_rad = speedControl.computeRad(event.getX(), event.getY());
speedControl.setDown_rad(down_rad);
break;
case MotionEvent.ACTION_MOVE:// 随着手指的move而不断进行重绘
final float current_move_rad = speedControl.computeRad(event.getX(), event.getY());
final float Δrad = current_move_rad - speedControl.getDown_rad();//计算手指滑过的弧度差
speedControl.setΔrad(Δrad);
//该方法在UI线程自身中使用
postInvalidate();
break;
case MotionEvent.ACTION_UP:// 随着手指的move而不断进行重绘
upTime = System.currentTimeMillis();
post(new Runnable() {
@Override
public void run() {
long duration = System.currentTimeMillis()-upTime;
if(duration ==stopTimeDuration ) {
return;
}else if(duration<stopTimeDuration) {
post(this);
}
//在非UI线程中使用。
invalidate();
}
});
break;
}
return true;
}
}
经过测试这个版本可以让风车随着手指移动速度的变化而变化,但是还是有个问题,就是手指抬起的时候同样的风车会停止转动,这个将在最后的版本来解决标签:android ontouchevent matirx
原文地址:http://blog.csdn.net/chunqiuwei/article/details/45438857