【Android Canvas系列】使用canvas绘制简单的clock

来源:互联网 发布:时时彩走势图软件 编辑:程序博客网 时间:2024/05/21 17:54

最近在看HTML5 canvas绘制方面的书籍,感觉和Anroid Canvas方面的知识有比较相通的地方。忽然萌生一个用Android Canvas实现书中例子程序的想法,一来巩固自己Android Canvas方面的知识,二来帮助一些想了解Android Canvas方面知识的新手们。

1. 目标

html5实现的clock截图
上图是使用HTML5 Canvas绘制的时钟,本次的目标就是使用Android Canvas实现一个一模一样的时钟。

2.API 列表

  • drawCircle //用于绘制钟表外框和中心的小圆点
  • drawText //用于绘制钟表外框上的文字
  • drawLine //用于绘制钟表的表针

3.代码分析

/** * Created by sogoe on 2015/3/14. */public class ClockView extends View {···    @override    protected void onDraw(Canvas canvas) {        if(!isInited)            initClock();        drawCircle(canvas);        drawCenter(canvas);        drawNumeral(canvas);        drawHands(canvas);        this.postInvalidateDelayed(1000);    }}

layout在计算完布局内每个view的长宽后,会调用view的draw函数。ondraw函数则会在draw函数中被调用,用于绘制内容。那么,关于钟表所有的绘制工作将会在ondraw函数内实现。initClock会执行相关参数的初始化工作,drawCircle是绘制钟表外圈园的函数,drawCenter是绘制钟表中心点的函数,drawNumeral是绘制钟表数字的函数,drawHands是绘制钟表表针的函数。注意,最后的postInvalidateDelayed函数,其内部实现也是使用handler.sendMessageDelayed,然后再handleMessage里执行invalidate函数。invalidate函数会请求重置整个view。

void initClock() {    height = this.getHeight();    width = this.getWidth();    padding = 35;    fontSize = 10;    int min = Math.min(this.getHeight(), this.getWidth());    radius = min/2 - padding;    handTruncation = min/25;    hourHandTruncation = min/10;    numeralRadius = radius + numeralSpacing;    paint = new Paint();    isInited = true;}

initClock函数就是对钟表的参数进行初始化。或许你会想,初始化为什么不放到构造函数里。仔细看,在代码第一二行里使用了getHeight和getWidth函数,如果放到构造函数里,获取到的长宽为0。因为,在view初始化的时候,系统也并不知道这个view的具体长宽,其父layout会不断调用view的onMeasure函数来计算这个view具体的长宽,所以,执行在ondraw之前,view的长宽才最终被确定下来。因此,在ondraw里执行长宽的初始化最保险。

void drawCircle(Canvas canvas) {    paint.reset();                                                                            paint.setColor(getResources().getColor(android.R.color.black));    paint.setStrokeWidth(1);    paint.setStyle(Paint.Style.STROKE);    paint.setAntiAlias(true);    canvas.drawCircle(width/2, height/2, radius, paint);}

drawCircle就是绘制一个圆圈,这里使用的paint设置style为stroke,表示仅绘制轮廓,不对其内部进行填充。下面的drawCenter函数则要将其设置为fill,因为要绘制一个实心的圆,所以要对其内部填充。

void drawCenter(Canvas canvas) {    paint.setStyle(Paint.Style.FILL);    canvas.drawCircle(width/2, height/2, 5, paint);}

将paint的style设置为fill,绘制实心圆。其他的设置沿用上面函数设置。

void drawNumeral(Canvas canvas) {     paint.setTextSize(fontSize);     float fontWidth;     double angle;     int x, y;     for (int number : numbers) {        fontWidth = paint.measureText(String.valueOf(number));        angle = Math.PI / 6 * (number - 3);        x = (int) (width / 2 + Math.cos(angle) * numeralRadius - fontWidth / 2);        y = (int) (height / 2 + Math.sin(angle) * numeralRadius + fontSize / 3);        canvas.drawText(String.valueOf(number), x, y, paint);     }}

首先设置字体的大小。留意paint.measureText函数,它返回按照paint当前的配置计算文本在屏幕上所占的长度,在canvas的文本绘制中相当有用。然后就是依次绘制钟表上的数字。x,y坐标点的计算可以在草稿纸上画一下,比较容易理解。

void drawHand(Canvas canvas, double loc, boolean isHour) {     double angle = Math.PI * loc / 30 - Math.PI / 2;     int handRadius = isHour ? radius - handTruncation - hourHandTruncation : radius - handTruncation;     canvas.drawLine(width / 2, height / 2,                (float) (width / 2 + Math.cos(angle) * handRadius),                (float) (height / 2 + Math.sin(angle) * handRadius),                paint); } void drawHands(Canvas canvas) {      Calendar calendar = Calendar.getInstance();      float hour = calendar.get(Calendar.HOUR_OF_DAY);      hour = hour > 12 ? hour - 12 : hour;      drawHand(canvas, (hour + calendar.get(Calendar.MINUTE) / 60.f) * 5.f, true);      drawHand(canvas, calendar.get(Calendar.MINUTE), false);      drawHand(canvas, calendar.get(Calendar.SECOND), false);}

绘制钟表表针的两个函数。需要留意的是drawLine函数,绘制从一个点至另一个点的直线。drawHands函数里,就是获取当前的时间,然后绘制针表,具体起始点和终点x,y的计算,在草稿纸上写写划划,很容易理解。

4.运行结果

Android运行结果

5.代码地址

GitHub代码地址

1 0