效果如下,实现一个标准的时钟效果,实现效果如下
其实原理很简单,分别绘制时针,分针和秒针,并且在时针,分针和秒针的顶端绘制对应的时间,根据时间对画布进行旋转
代码如下
主Activity.java
public class CustomActivity extends Activity {
private MyClockView mMyClockView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_layout);
mMyClockView = this.findViewById(R.id.clock_view);
}
}
主页面
package com.hwj.custom.clock.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import java.util.Calendar;
public class MyClockView extends View {
private int centerX;
private int centerY;
private int circleDadius;
private Paint mCirlePaint;
private Paint mTimePaint;
private Handler tickHandler;
public MyClockView(Context context){
super(context);
initClockView(context);
}
public MyClockView(Context context, AttributeSet attrs){
super(context, attrs);
initClockView(context);
}
private void initClockView(Context context){
//为了避免onDraw方法不调用,从而调用了setWillNotDraw();
// setWillNotDraw(false);
mCirlePaint = new Paint();
mCirlePaint.setColor(Color.BLACK);
mCirlePaint.setStyle(Paint.Style.STROKE);
mCirlePaint.setAntiAlias(true);
mTimePaint = new Paint();
mTimePaint.setColor(Color.RED);
mTimePaint.setStyle(Paint.Style.STROKE);
mTimePaint.setAntiAlias(true);
run();
}
public void run()
{
tickHandler = new Handler();
tickHandler.post(tickRunnable);
}
private Runnable tickRunnable = new Runnable()
{
public void run()
{
postInvalidate();
tickHandler.postDelayed(tickRunnable, 10);
}
};
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取圆心
centerX = this.getMeasuredWidth() / 2;
centerY = this.getMeasuredHeight() / 2;
//设置圆的半径
if(centerX > centerY){
circleDadius = centerY;
}else{
circleDadius = centerX;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// showInitClock(canvas);
updateClockView(canvas);
}
/*
* 首次展示时的页面,其实展示的就是时针,分针,秒针重合的一个view
*/
private void showInitClock(Canvas canvas){
canvas.drawCircle(centerX,centerY,circleDadius,mCirlePaint);
//绘制时针
mTimePaint.setStrokeWidth(5);
canvas.drawLine(centerX,centerY,centerX,0 + 50,mTimePaint);
canvas.save();
canvas.restore();
//绘制分针
mTimePaint.setStrokeWidth(3);
canvas.drawLine(centerX,centerY,centerX,0 + 20,mTimePaint);
canvas.save();
canvas.restore();
//绘制秒针
mTimePaint.setStrokeWidth(1);
canvas.drawLine(centerX,centerY,centerX,0,mTimePaint);
canvas.save();
canvas.restore();
}
/*
* 更新view区域,其原理就是旋转画布,重新绘制时针,分针和秒针
*/
private void updateClockView(Canvas canvas){
canvas.drawCircle(centerX,centerY,circleDadius,mCirlePaint);
//获取当前时间
Calendar cal = Calendar.getInstance();
//Calendar.HOUR是12小时制
int hour = cal.get(Calendar.HOUR);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
//一个时钟标记为12小时,一个圆是360度,共12段,顾一个小时的旋转角度为360 / 12 = 30
//一个时钟标记为12小时,一个圆是360度,共60段,顾则每等分的角度为 360 / 60 = 6,即每分钟的旋转角度
//一个时钟标记为12小时,一个圆是360度,共60段,即每秒旋转角度为 360 / 60 = 6
float hourDegree = hour * (360 / 12) + minute * (360 / (60 * 12));
float minDegree = minute * (360 / (12 * 5)) + second * (360 / (60 * 60 * 12));
float secDegree = second * (360 / (12 * 5));
//顾我们可以总体计算出时针,分针,秒针的计算方法
//时针转动角度 = 小时角度 + 分钟角度,分针和秒针 以此类推
//需要说明的是,这里的分钟角度为什么不能使用minute * (360 / (12 * 5))来计算,
//这是因为minute * (360 / (12 * 5))表示时钟总共被分针分割为60份,每份表示6度,不等于于现实里面每分钟的角度
//绘制时针
mTimePaint.setStrokeWidth(5);
canvas.save();
canvas.rotate(hourDegree, centerX, centerY);
canvas.drawLine(centerX,centerY,centerX,0 + 50,mTimePaint);
hour = (hour == 0) ? 12 : hour;
canvas.drawText(String.valueOf(hour),centerX,0 + 50,mCirlePaint);
canvas.restore();
//绘制分针
mTimePaint.setStrokeWidth(3);
canvas.save();
canvas.rotate(minDegree, centerX, centerY);
canvas.drawLine(centerX,centerY,centerX,0 + 20,mTimePaint);
canvas.drawText(String.valueOf(minute),centerX,0 + 20,mCirlePaint);
canvas.restore();
//绘制秒针
mTimePaint.setStrokeWidth(1);
canvas.save();
canvas.rotate(secDegree, centerX, centerY);
canvas.drawLine(centerX,centerY,centerX,0,mTimePaint);
canvas.drawText(String.valueOf(second),centerX,0,mCirlePaint);
canvas.restore();
}
}
主xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.hwj.custom.clock.view.CustomActivity">
<com.hwj.custom.clock.view.MyClockView
android:id="@+id/clock_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.hwj.custom.clock.view.MyClockView>
</LinearLayout>
问题一:如果是继承自LinearLayout,不触发onDraw
解决方案1:调用setWillNotDraw(false)
解决方案2:继承View