Android绘制时钟

最近在学View相关的知识,对Canvas和Paint类有了初步了解,看到别人弄了一个会走动的时钟,自己也打算给弄上一个,算是巩固一下相关知识。效果图如下:




首先来分析一下,要绘制出一个时钟,要绘制哪几部分:时钟的大圆、圆上的刻度线、圆外的数字、圆中心处的圆点以及三个时钟指针。既然明白了要绘制的东西,下面只需要想办法来实现即可。

(1)绘制时钟的大圆

这个最简单,只要确定好圆中心坐标点和半径即可

(2)绘制圆上的刻度线

一个时钟总共60个刻度线,通过canvas的rotate()方法,进行不断的旋转,每次旋转的角度为360/60;

(3)绘制圆外的数字

和上面一样,进行旋转绘制即可;

(4)绘制圆中心处的圆点

和(1)一样,只是注意更改一下画笔的设置;

(5)绘制三个时钟指针

根据当前的时分秒,计算出每个指针的旋转角度,在直接绘制线段即可;


注意到,时钟是每秒走一次,也即我们每秒就要刷新一次界面,重复一次上面的绘制工作。所以,一初始化时钟View的时刻,我们通过Handler弄一个定时器,每秒进行刷新操作。


ClockView源码如下:

package com.scu.lly.drawclock.view;

import java.util.Calendar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;

public class ClockView extends View {
	
	private Paint mPaint;
	/**
	 * 描边线的粗细
	 */
	private int strokeWidth = 2;
	/**
	 * 时钟是否在走(即是否第一次onDraw)
	 */
	private boolean isRunning;
	
	private Handler mHandler;
	private Runnable clockRunnable;
	
	/**
	 * 时钟圆的半径
	 */
	private int radius = 150;
	
	private String[] clockNumbers = {"12","1","2","3","4","5","6","7","8","9","10","11"};
	/**
	 * 时钟上需要绘制的数字
	 */
	private String num;
	
	/**
	 * 用于测量文本的宽、高度(这里主要是来获取高度)
	 */
	private Rect textBounds = new Rect();
	
	private Calendar cal;
	
	private int hour,min,second;
	private float hourAngle,minAngle,secAngle;

	public ClockView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public ClockView(Context context) {
		super(context);
		init();
	}

	private void init() {
		mPaint = new Paint();
		mHandler = new Handler();
//		cal = Calendar.getInstance();
		clockRunnable = new Runnable() {//里面做的事情就是每隔一秒,刷新一次界面
			@Override
			public void run() {
				//线程中刷新界面
				postInvalidate();
				mHandler.postDelayed(this, 1000);
			}
		};
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if(!isRunning){
			runClock();
		}else{
			initPaint();
			//绘制圆形部分
			drawClockCircle(canvas);
			//绘制刻度线
			drawClockScale(canvas);
			//绘制数字
			drawClockNumber(canvas);
			//绘制中心原点
			drawClockDot(canvas);
			//绘制三个指针
			drawClockPoint(canvas);
		}
	}
	
	/**
	 * 绘制三个指针
	 * @param canvas
	 */
	private void drawClockPoint(Canvas canvas) {
		cal = Calendar.getInstance();
		hour = cal.get(Calendar.HOUR);//Calendar.HOUR获取的是12小时制,Calendar.HOUR_OF_DAY获取的是24小时制
		min = cal.get(Calendar.MINUTE);
		second = cal.get(Calendar.SECOND);
		//计算时分秒指针各自需要偏移的角度
		hourAngle = (float)hour / 12 * 360 + (float)min / 60 * (360 / 12);//360/12是指每个数字之间的角度
		minAngle = (float)min / 60 * 360;
		secAngle = (float)second / 60 * 360;
		//下面将时、分、秒指针按照各自的偏移角度进行旋转,每次旋转前要先保存canvas的原始状态
		canvas.save();
		canvas.rotate(hourAngle,getWidth() / 2, getHeight() / 2);
		canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2 - 65, mPaint);//时针长度设置为65
		
		canvas.restore();
		canvas.save();
		canvas.rotate(minAngle,getWidth() / 2, getHeight() / 2);
		canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2 - 90 , mPaint);//分针长度设置为90
		
		canvas.restore();
		canvas.save();
		canvas.rotate(secAngle,getWidth() / 2, getHeight() / 2);
		canvas.drawLine(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2 - 110 , mPaint);//秒针长度设置为110
		
		canvas.restore();
	}

	/**
	 * 绘制中心原点
	 */
	private void drawClockDot(Canvas canvas) {
		mPaint.reset();
//		mPaint.setAntiAlias(true);
		mPaint.setColor(Color.RED);
		mPaint.setStyle(Paint.Style.FILL);
		canvas.drawCircle(getWidth() / 2, getHeight() / 2, 6, mPaint);
		initPaint();
	}

	/**
	 * 绘制数字(从正上方12点处开始绘制)
	 * @param canvas
	 */
	private void drawClockNumber(Canvas canvas) {
		//先保存一下当前画布的状态,因为后面画布会进行旋转操作,而在绘制完刻度后,需要恢复画布状态
		canvas.save();
//		mPaint.setStrokeWidth(2);
		mPaint.setTextSize(25);
		//计算12点处 数字 的坐标
		int preX = getWidth() / 2;
		int preY = getHeight() / 2 - radius - strokeWidth - 10;//10为圆与数字文本之间的间距
		//x,y才是文本真正的准确坐标,需要减去文本的自身宽、高因素
		int x,y;
		//计算画布每次需要旋转的角度
		int degree = 360 / clockNumbers.length;
		for(int i = 0; i < clockNumbers.length; i++){
			num = clockNumbers[i];
			mPaint.getTextBounds(num, 0, num.length(), textBounds);
			x = (int) (preX - mPaint.measureText(num) / 2);
			y = preY - textBounds.height();//从文本的中心点处开始绘制
			canvas.drawText(num, x, y, mPaint);
			canvas.rotate(degree, getWidth() / 2, getHeight() / 2);//以圆中心进行旋转
		}
		//绘制完后,记得把画布状态复原
		canvas.restore();
	}

	/**
	 * 绘制刻度线(总共60条)
	 * 从正上方,即12点处开始绘制一条直线,后面的只是旋转一下画布角度即可
	 * @param canvas
	 */
	private void drawClockScale(Canvas canvas) {
		//先保存一下当前画布的状态,因为后面画布会进行旋转操作,而在绘制完刻度后,需要恢复画布状态
		canvas.save();
		//计算12点处刻度的开始坐标
		int startX = getWidth() / 2;
		int startY = getHeight() / 2 - radius;//y坐标即园中心点的y坐标-半径
		//计算12点处的结束坐标
		int stopX = startX;
		int stopY1 = startY + 30;//整点处的线长度为30
		int stopY2 = startY + 15;//非整点处的线长度为15
		//计算画布每次旋转的角度
		float degree = 360 / 60;
		for(int i = 0; i < 60; i++){
			if(i % 5 == 0)
				canvas.drawLine(startX, startY, stopX, stopY1, mPaint);//绘制整点长的刻度
			else
				canvas.drawLine(startX, startY, stopX, stopY2, mPaint);//绘制非整点处短的刻度
			canvas.rotate(degree, getWidth() / 2, getHeight() / 2);//以圆中心进行旋转
		}
		//绘制完后,记得把画布状态复原
		canvas.restore();
	}

	/**
	 * 绘制时钟的圆形部分
	 * @param canvas
	 */
	private void drawClockCircle(Canvas canvas) {
		//获得圆的圆点坐标
		int x = getWidth() / 2;
		int y = getHeight() / 2;
		canvas.drawCircle(x, y, radius, mPaint);
	}
	
	private void initPaint() {
		mPaint.reset();
		mPaint.setColor(Color.RED);
		mPaint.setStyle(Paint.Style.STROKE);//设置描边
		mPaint.setStrokeWidth(strokeWidth);//设置描边线的粗细
		mPaint.setAntiAlias(true);//设置抗锯齿,使圆形更加圆滑
	}

	private void runClock() {
		isRunning = true;
		mHandler.postDelayed(clockRunnable, 1000);
	}
	

}

注:上面一些计算只要把草图画好,计算坐标就好。


缺陷:

从效果图中可以看到一个明显的不足就是,绘制的数字按一个方向旋转后,效果不满意。我尝试了分段绘制,比如将12个数字分成四组{12,,1,2},{3,4,5},{6,7,8},{9,10,11},还是不尽人意。我最主要的问题就是卡在canvas的rotate()旋转方法的理解上,查了很多资料,基本上认同的是旋转的坐标,看时钟的效果也的确如此,但是目前主要是对rotate方法理解不够深入,不能进行灵活应用。

有优化的方案及其他不足之处,还请各位同学多多提意见。


点此源码下载



  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
可以使用Python中的turtle模块来绘制时钟。具体步骤如下: 1. 导入turtle模块 2. 创建一个画布,并设置画布的大小和背景颜色 3. 创建一个turtle对象,并设置画笔的颜色和粗细 4. 绘制时钟的外框,可以使用turtle的circle()函数来绘制圆形 5. 绘制时钟的刻度,可以使用turtle的penup()和pendown()函数来控制画笔的移动,然后使用forward()函数来绘制线条 6. 绘制时钟的指针,可以使用turtle的setheading()函数来设置指针的方向,然后使用forward()函数来绘制指针 7. 最后,使用turtle的done()函数来保持窗口的显示,直到用户关闭窗口为止。 示例代码如下: ```python import turtle import time # 设置画布大小和背景颜色 turtle.setup(600, 600) turtle.bgcolor("white") # 创建一个turtle对象,并设置画笔的颜色和粗细 pen = turtle.Turtle() pen.color("black") pen.pensize(3) # 绘制时钟的外框 pen.penup() pen.goto(, -200) pen.pendown() pen.circle(200) # 绘制时钟的刻度 for i in range(12): pen.penup() pen.goto(, ) pen.setheading(30 * i - 90) pen.forward(170) pen.pendown() pen.forward(20) # 绘制时钟的指针 while True: t = time.localtime() hour = t.tm_hour % 12 minute = t.tm_min second = t.tm_sec pen.penup() pen.goto(, ) pen.setheading(30 * hour + minute / 2 - 90) pen.pendown() pen.forward(80) pen.penup() pen.goto(, ) pen.setheading(6 * minute - 90) pen.pendown() pen.forward(120) pen.penup() pen.goto(, ) pen.setheading(6 * second - 90) pen.pendown() pen.forward(150) time.sleep(1) pen.clear() turtle.done() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值