码迷,mamicode.com
首页 > 其他好文 > 详细

自定义View之大风车系列demo(四)

时间:2015-05-02 13:56:09      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:android   matirx   

版本4.0有个问题当手指抬起的时候风车停止了,现在就解决这个问题,手指抬起的时候继续让风车由于惯性而继续旋转一段时间。思路如下

1)需要获取手指抬起时风车转动的瞬间速度,这个难度不小,在我的demo里面我只是简单的计算了手指按下到抬起经过的时间和弧度差,用弧度差除以时间来模拟下速度。

具体的还真不好用语言描述,所以偷个懒,直接上代码吧速度控制器添加了speed变量,并根据弧度差和经过的时间来计算速度


package rotation.demo.bean;

import android.util.Log;


/***
 * 当手指移动的时候,补货手指抬起时风车转动的瞬间的速度:在这里暂且模拟为手指按下到抬起时的弧度减去按下时的弧度,除以经过的时间
 * @author YanQiu
 *
 */
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;
	
	/**手指抬起时的速度**/
	private float speed;
	
	public SpeedControl(float x0, float y0) {
		this.x0 = x0;
		this.y0 = y0;
	}
	
/*	*//**
	 * 判断是否是顺时针
	 * @param current_move_x 手指
	 * @param current_move_y
	 * @param up_x
	 * @param up_y
	 * @return
	 *//*
	public boolean isClockWise(float current_move_x,float current_move_y,float up_x,float up_y) {
		return false;
	}
*/
	/***
	 * 计算当前坐标点与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θ);
			}
		}

		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;
	}

	public float getΔrad() {
		return Δrad;
	}

	public void setΔrad(float δrad) {
		Δrad = δrad;
	}

	public float getSpeed() {
		return speed;
	}

	public void setSpeed(float δrad,long duration) {
		
		δrad = 1000*Math.abs(δrad);
		Log.e("", "δrad==="+δrad + "---duration=="+duration + " speed =="+Math.abs(δrad/duration));
		this.speed = Math.abs(δrad/duration);
	}

}

RotationView代码修改如下,主要修改了action_up事件和post的Ruannable方法:

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

	/**手指滑动时此时的时间**/
	private long current_move_time;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			final float down_rad = speedControl.computeRad(event.getX(), event.getY());
			speedControl.setDown_rad(down_rad);
			current_move_time = System.currentTimeMillis();
			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而不断进行重绘
			final float up_rad = speedControl.computeRad(event.getX(), event.getY());
			//手指抬起和按下经过的弧度差
			final float δrad = up_rad - speedControl.getDown_rad();
			upTime = System.currentTimeMillis();
			final long  duration = upTime - current_move_time;
			//设置手指离开时的速度
			speedControl.setSpeed(δrad, duration);
			post(new Runnable() {
				@Override
				public void run() {
					long stopDuration = System.currentTimeMillis()-upTime;
					//long  
					//speedControl.setSpeed(duration);
					if(stopDuration == stopTimeDuration) {
						return;
					}else if(stopDuration<stopTimeDuration){
						post(this);
					}
					//计算此时转过的弧度
					speedControl.setΔrad(speedControl.getSpeed()*1000/stopDuration);
					invalidate();
				}
			});
			
			break;
		}
		//此处必须返回true,否则不会执行此处的事件,详见博客
		return true;
	}

}

到此为止,捣鼓了半天的小demo终于完成了,不过还有个问题:经过这一修改,不知道怎么判断手指是否是逆时针还是顺时针转动了,查了好些资料好些解决不了问题,希望有好的建议或者思路的给留个言.还有计算惯性转动的弧度不是很好,只是简单的模拟,风车逐渐停止的效果不是很理想

自定义View之大风车系列demo(四)

标签:android   matirx   

原文地址:http://blog.csdn.net/chunqiuwei/article/details/45439019

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!