1.表盘一效果图
忽略小球上下移动。。。这个是重力感应下上下移动的。
本功能的主要实现是,三个背景圆圈的旋转。
首先,这三个圆需要无线旋转。
其次,需要根据不同的情况,加速,或者减速旋转。
不知道大家怎么想的,我最开始想到的就是利用,RotateAnimation,来实现旋转效果。new的时候,可以传入旋转的初始角度,和目的角度。setDuration(..),就实现了旋转的效果。
但是,android提供的这个旋转,从起始角度,到终点角度,在一定的时间范围呢,速度你是不可以控制的,什么时候旋转多块,都是不可控制的。这肯定不符合我们的需求。
而且,每次重新设置旋转时间的时候,都会有明显的卡顿。(重置嘛,整理好了重新开始旋转)。
后来使用了Canvas.rotate(旋转的度数,旋转中心x,旋转中心y)。相当于整个画板旋转。
核心思想,是在onDraw中,调用此方法。创建一个handler,每隔一段时间发送执行一次invalidate()方法。系统又会执行ondraw方法,就显示了既可以控制旋转速度,也可以无线旋转的效果。
package lenovo.com.keyguardtheme2;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
/**
* Created by Administrator on 2016/2/15.
*/
public class RotateImageView extends ImageView {
private int measuredHeight;
private int measuredWidth;
private long old;
private int mRotateTime = 18000;
private int degreeTime;
private int i = 0;
private Handler handler;
private Runnable runnable;
private int mOrientation;
public RotateImageView(Context context) {
super(context);
}
public RotateImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
measuredHeight = this.getMeasuredHeight();
measuredWidth = this.getMeasuredWidth();
}
@Override
protected void onDraw(Canvas canvas) {
//左
if(mOrientation == 0){
canvas.rotate(i--, measuredWidth / 2, measuredHeight / 2);
//右
}else{
canvas.rotate(i++, measuredWidth / 2, measuredHeight / 2);
}
super.onDraw(canvas);
}
//冲外部设置动画旋转的时间
public void setRotateTime(int time){
mRotateTime = time;
degreeTime = mRotateTime / 360;
}
//开启旋转动画
public void startRotateAnimation(){
handler = new Handler();
runnable = new Runnable() {
@Override
public void run() {
invalidate();
handler.postDelayed(this, degreeTime);
}
};
handler.postDelayed(runnable, degreeTime);
Log.i("qq","run.........................");
}
//关闭动画
public void finishAnimation(){
if(handler!=null && runnable != null){
handler.removeCallbacks(runnable);
}
}
/**
* 设置圆环的旋转方向
* 0:left
* 1:right
*/
public void setRotateDirection(int orientation){
mOrientation = orientation;
}
}
2.表盘2 效果图
这张图大家看的可能不是太清楚。
一个表盘,北京是3个圆圈,分别代表时针,分针,秒针所对应的圆环。图片正中间显示当前的时间。
需求,就是随着时间的变化,显示由时针,分针,秒针所围成的三角形。
其实也很简单。
1.时针,分针,秒针,每转动一次旋转多少角度?
2.计算当前时间,对应的时分秒的角度。
3.根据角度,时分秒的半径,计算当前时分秒的针尖的坐标。
4.利用Path将其连接在一起。
提醒下自己,以前总觉得Math这个类用起来很方便,Math.sin(30);就算出角度是30的sin值了。。
后来才发现TM的是错误的。java要求你传入的是弧度值。
所以,如果要求30度对应的cos值,应该这么求
Math.cos(Math.toRadians(degree))
<span style="font-size:18px;">package lenovo.com.keyguardtheme4;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import java.util.Calendar;
/**
* Created by Administrator on 2016/2/15.
*/
public class RotateImageViewWatch4 extends ImageView {
private int measuredHeight;
private int measuredWidth;
private Context mContext;
private Handler handler;
private Runnable runnable;
private int heightPixels;
private int widthPixels;
private Calendar calendar;
/**
* 时针
*/
private int hourDegree = 30; //每秒旋转的度数
private int currentHourDegree = 0;//当前旋转的度数
/**
* 分种
*/
private int minuteDegree = 6; //每秒旋转的度数
private int currentMinuteDegree = 0;//当前旋转的度数
/**
* 秒针
*/
private int secondDegree = 6; //每秒旋转的度数
private int currentSecondDegree = 0;//当前旋转的度数
/**
* 时针半径
*/
private int hRadius = 134;
/**
* 分针半径
*/
private int mRadius = 170;
/**
* 秒针半径
*/
private int sRadius = 206;
/**
* 小时指针的坐标
*/
private int[] h = new int[2];
/**
* 分针指针的坐标
*/
private int[] m = new int[2];
/**
* 秒指针的坐标
*/
private int[] s = new int[2];
private Paint paint;
private Path path;
public RotateImageViewWatch4(Context context) {
super(context);
init(context);
}
public RotateImageViewWatch4(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mContext = context;
heightPixels = mContext.getResources().getDisplayMetrics().heightPixels;
widthPixels = mContext.getResources().getDisplayMetrics().widthPixels;
paint = new Paint();
paint.setColor( Color.argb(205, 00, 210, 255));
paint.setAntiAlias(true);
paint.setStrokeWidth(5.0f);
paint.setStyle(Paint.Style.FILL);
Log.i("2016.2.25", "屏幕的高度==" + heightPixels);
Log.i("2016.2.25", "屏幕的宽度==" + widthPixels);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
measuredHeight = this.getMeasuredHeight();
measuredWidth = this.getMeasuredWidth();
}
@Override
protected void onDraw(Canvas canvas) {
calculateDegree();
super.onDraw(canvas);
path = new Path();
path.reset();
path.moveTo(h[0],h[1]);
path.lineTo(m[0],m[1]);
path.lineTo(s[0],s[1]);
path.close();
canvas.drawPath(path,paint);
Log.i("2016.2.25", "ondraw---------------------------");
Log.i("2016.2.25", "h[0]=" + h[0] + " h[1]=" + h[1] + " m[0]="+m[0]
+" m[1]="+m[1]+" s[0]="+s[0]+" s[1]="+s[1]);
}
/**
* 当前时间
*/
private int currentHour = 0;
private int currentMinute = 0;
private int currentSecond = 0;
private void calculateDegree() {
//每次将时间清零
currentHour = 0;
currentMinute = 0;
currentSecond = 0;
//当前时间
calendar = Calendar.getInstance();
currentHour = calendar.get(Calendar.HOUR);
currentMinute = calendar.get(Calendar.MINUTE);
currentSecond = calendar.get(Calendar.SECOND);
//应该旋转的度数
currentHourDegree = hourDegree * currentHour;
currentMinuteDegree = minuteDegree * currentMinute;
currentSecondDegree = secondDegree * currentSecond;
//当前时针所在的坐标
h = calcuateXY(hRadius,currentHourDegree);
//当前分针所在的坐标
m = calcuateXY(mRadius,currentMinuteDegree);
//当前秒针所在的坐标
s = calcuateXY(sRadius,currentSecondDegree);
Log.i("2016.2.25","h[0]="+h[0]+" s[0]="+s[0]);
}
/**
* 根据当前的旋转角度 计算半径与圆边交点所对应的x,y的值
* @return
*/
private int x,y;
private int[] calcuateXY(int radius,int degree){
int[] xy = new int[2];
if(degree == 0){
x = 0;
y = radius;
xy[0] = measuredWidth / 2;
xy[1] = measuredHeight / 2 - radius;
}else if(degree > 0 && degree <90){
x = (int) (radius * Math.sin(Math.toRadians(degree)));
y = (int) (radius * Math.cos(Math.toRadians(degree)));
xy[0] = measuredWidth / 2 + x;
xy[1] = measuredHeight / 2 - y;
}else if(degree == 90){
x = radius;
y = 0;
xy[0] = measuredWidth / 2 + radius;
xy[1] = measuredHeight / 2 ;
}else if(degree > 90 && degree < 180){
degree = degree - 90;
x = (int) (radius * Math.cos(Math.toRadians(degree)));
y = (int) (radius * Math.sin(Math.toRadians(degree)));
xy[0] = measuredWidth / 2 + x;
xy[1] = measuredHeight / 2 + y ;
}else if(degree == 180){
x = 0;
y = radius;
xy[0] = measuredWidth / 2;
xy[1] = measuredHeight / 2 + radius ;
}else if(degree > 180 && degree < 270){
degree = degree - 180;
x = (int) (radius * Math.sin(Math.toRadians(degree)));
y = (int) (radius * Math.cos(Math.toRadians(degree)));
xy[0] = measuredWidth / 2 - x;
xy[1] = measuredHeight / 2 + y ;
}else if(degree == 270 ){
x = radius;
y = 0;
xy[0] = measuredWidth / 2 - radius;
xy[1] = measuredHeight / 2;
}else if(degree > 270 && degree < 360){
degree = degree - 270;
x = (int) (radius * Math.cos(Math.toRadians(degree)));
y = (int) (radius * Math.sin(Math.toRadians(degree)));
xy[0] = measuredWidth / 2 - x;
xy[1] = measuredHeight / 2 -y ;
}else if(degree == 360){
x = 0;
y = radius;
xy[0] = measuredWidth / 2;
xy[1] = measuredHeight / 2 - radius ;
}
// Log.i("2016.2.25","x===="+x+" y==="+y);
Log.i("2016.2.25","xy[0]===="+xy[0]+" xy[1]==="+xy[1]);
return xy;
}
//开启旋转动画
public void startRotateAnimation(){
handler = new Handler();
runnable = new Runnable() {
@Override
public void run() {
invalidate();
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(runnable, 1000);
Log.i("qq","run.........................");
}
//关闭动画
public void finishAnimation(){
if(handler!=null && runnable != null){
handler.removeCallbacks(runnable);
}
}
}</span>