实现的效果图如下:
main中布局文件:
<com.example.drawtime.MyClock
android:layout_width="match_parent"
android:layout_height="match_parent" />
values文件夹下新建一个xml文件,定义参数
<resources>
<declare-styleable name="MyView">
<attr name="MyView_color" format="color"/>
<attr name="MyView_radius" format="float"/>
</declare-styleable>
</resources>
1.自定义一个类 MyClock extends View,并设置统一的入口
public MyClock(Context context) {
this(context, null);
}
public MyClock(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyClock(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyView, defStyleAttr, 0);
//获得xml属性
color = typedArray.getColor(R.styleable.MyView_MyView_color, CIRCLE_CLOCK);
radius = typedArray.getFloat(R.styleable.MyView_MyView_radius, CIRCLE_RADIUS);
typedArray.recycle();
}
2.测量控件的宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureHeight(int heightMeasureSpec) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
heightResult = size;
} else {
heightResult = 600;
if (mode == MeasureSpec.AT_MOST) {
heightResult = Math.min(heightResult, size);
}
}
return heightResult;
}
private int measureWidth(int widthMeasureSpec) {
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
widthResult = size;
} else {
widthResult = 600;//给一个默认的宽度
if (mode == MeasureSpec.AT_MOST) {
widthResult = Math.min(widthResult, size);
}
}
return widthResult;
}
3.----------------------现在就要开始绘制了---------------------------
我把他们封装为方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制表盘
BiaoPan(canvas);
//绘制logo
Logo(canvas);
//绘制数字时间
Time(canvas);
//画刻度
drgree(canvas);
//画表盘时间数字
HourText(canvas);
mHandler.sendEmptyMessage(HANDLER_MSG);
//画时针
canvas.save();
hour(canvas);
canvas.restore();
//画分针
canvas.save();
minutes(canvas);
canvas.restore();
//画秒针
canvas.save();
second(canvas);
canvas.restore();
//画中间小点
Point(canvas);
}
3.1绘制表盘
private void BiaoPan(Canvas canvas) {
mBiaoPan = new Paint();
mBiaoPan.setAntiAlias(true);
canvas.translate(widthResult / 2, heightResult / 2);
mBiaoPan.setStyle(Paint.Style.STROKE);
mBiaoPan.setColor(color);
mBiaoPan.setStrokeWidth(2);
canvas.drawCircle(0, 0, radius, mBiaoPan);
}
3.2绘制Logo,正负代表方向
private void Logo(Canvas canvas) {
mLogoPaint = new TextPaint();
mLogoPaint.setColor(Color.parseColor("#FF4081"));
mLogoPaint.setAntiAlias(true);
mLogoPaint.setStyle(Paint.Style.STROKE);
mLogoPaint.setStrokeWidth(2);
mLogoPaint.setTextSize(50);
float textwith = mLogoPaint.measureText(BIAO_LOGO);
canvas.drawText(BIAO_LOGO, -textwith / 2, -radius / 5 * 2, mLogoPaint);
}
3.3绘制数字的时间,默认 00:00:00
private void Time(Canvas canvas) {
mTimePaint = new Paint();
mTimePaint.setAntiAlias(true);
mTimePaint.setColor(Color.GREEN);
mTimePaint.setStyle(Paint.Style.FILL);
mTimePaint.setTextSize(45);
/**根据实际情况我们需要判断下时分秒的数字是不是小于10,如果是前面补一位0*/
if (mSecond < 10) {
replaceMsecond = "0" + String.valueOf(mSecond).replace(".0", "");
} else {
replaceMsecond = String.valueOf(mSecond).replace(".0", "");
}
if (mMinutes < 10) {
replaceMminutes = "0" + String.valueOf(mMinutes).replace(".0", "");
} else {
replaceMminutes = String.valueOf(mMinutes).replace(".0", "");
}
if (mHour < 10) {
replaceMhour = "0" + String.valueOf(mHour).replace(".0", "");
} else {
replaceMhour = String.valueOf(mHour).replace(".0", "");
}
float v = mTimePaint.measureText(replaceMhour + replaceMminutes + replaceMsecond + ":" + ":");
canvas.drawText(replaceMhour + ":" + replaceMminutes + ":" + replaceMsecond, -v / 2, radius / 3 * 2, mTimePaint);
}
3.4绘制刻度线(让画布旋转)
private void drgree(Canvas canvas) {
mDegreePaint = new Paint();
mDegreePaint.setAntiAlias(true);
mDegreePaint.setStyle(Paint.Style.FILL);
mDegreePaint.setColor(Color.BLACK);
mDegreePaint.setStrokeWidth(5);
int count = 60;
for (int i = 0; i < count; i++) {
if (i % 5 == 0) {
canvas.drawLine(0, radius, 0, radius - 40, mDegreePaint);
} else {
canvas.drawLine(0, radius, 0, radius - 15, mDegreePaint);
}
canvas.rotate(360 / count, 0f, 0f);
}
}
3.5 画表盘上的数字
private void HourText(Canvas canvas) {
mHourTextPaint = new Paint();
mHourTextPaint.setStyle(Paint.Style.FILL);
mHourTextPaint.setStrokeWidth(2);
mHourTextPaint.setAntiAlias(true);
mHourTextPaint.setTextSize(55);
mHourTextPaint.setColor(Color.DKGRAY);
mHourTextPaint.setTextAlign(Paint.Align.CENTER);
float textheight = mHourTextPaint.getFontMetrics().bottom - mHourTextPaint.getFontMetrics().top;
float distance = radius - 70;
float a, b;
for (int i = 0; i < 12; i++) {
a = (float) (distance * Math.sin(i * 30 * Math.PI / 180));
b = (float) (distance * Math.cos(i * 30 * Math.PI / 180));
if (i == 0) {
canvas.drawText("12", a, -b + textheight / 3, mHourTextPaint);
} else {
canvas.drawText(String.valueOf(i), a, -b + textheight / 3, mHourTextPaint);
}
}
}
3.6 发送一条空消息,让时间数字,走起来
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case HANDLER_MSG:
invalidate();
long time = System.currentTimeMillis();
mSecond = (time / 1000 % 60);
mMinutes = (time / 1000 / 60 % 60);
mHour = (time / 1000 / 60 / 60 + 8) % 12;
break;
}
return true;
}
3.7画时针分针秒针(必须要先保存之前的画的,不然会一起动)
private void hour(Canvas canvas) { mHourPaint = new Paint(); mHourPaint.setStrokeWidth(10); mHourPaint.setAntiAlias(true); mHourPaint.setStyle(Paint.Style.FILL); mHourPaint.setColor(Color.RED); canvas.rotate(mHour * 30 + mMinutes / 60 * 30, 0, 0);//其中mMinutes/60*30为时钟偏移的角度 canvas.drawLine(0, 20, 0, -(radius -320), mHourPaint); }
private void minutes(Canvas canvas) { mMinutesPaint = new Paint(); mMinutesPaint.setStrokeWidth(8); mMinutesPaint.setAntiAlias(true); mMinutesPaint.setColor(Color.BLUE); mMinutesPaint.setStyle(Paint.Style.FILL); canvas.rotate(mMinutes * 6, 0, 0); canvas.drawLine(0, 20, 0, -(radius - 200), mMinutesPaint); }
private void second(Canvas canvas) { //画秒针 mSecondPaint = new Paint(); mSecondPaint.setStrokeWidth(5); mSecondPaint.setAntiAlias(true);//设置抗锯齿 mSecondPaint.setColor(Color.GREEN); mSecondPaint.setStyle(Paint.Style.FILL); canvas.rotate(mSecond * 6, 0, 0); canvas.drawLine(0, 30, 0, -(radius - 100), mSecondPaint); }
3.8 最后在中心画点把指针覆盖private void Point(Canvas canvas) { mPointPaint = new Paint(); mPointPaint.setStrokeWidth(5); mPointPaint.setStyle(Paint.Style.FILL); mPointPaint.setColor(Color.BLACK); canvas.drawCircle(0, 0, 12, mPointPaint); }
直接的粘的代码,看的不是很清楚,慢慢看咯