【Android Canvas系列】使用canvas绘制简单的clock
来源:互联网 发布:时时彩走势图软件 编辑:程序博客网 时间:2024/05/21 17:54
最近在看HTML5 canvas绘制方面的书籍,感觉和Anroid Canvas方面的知识有比较相通的地方。忽然萌生一个用Android Canvas实现书中例子程序的想法,一来巩固自己Android Canvas方面的知识,二来帮助一些想了解Android Canvas方面知识的新手们。
1. 目标
上图是使用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.运行结果
5.代码地址
GitHub代码地址
- 【Android Canvas系列】使用canvas绘制简单的clock
- [Canvas系列]Canvas简单线条绘制_02
- Android中使用Canvas绘制简单的图形(一)
- Android-使用OpengGL实现的Canvas进行绘制(简单介绍)
- 使用canvas简单绘制心电图
- Android中使用Canvas绘制简单的图形(二) 进阶 绘制钟表
- 绘制Canvas的使用二
- html5之canvas绘制图形的简单使用
- android Paint 和Canvas的简单使用
- clock-canvas
- Canvas绘制钟表插件 clock-plug-in
- android 用canvas 绘制简单圆形时钟
- Android 使用Canvas中的drawBitmap方法绘制拉伸的图片
- android canvas的使用
- Android Canvas 的使用
- [Canvas系列]Canvas绘制圆弧形状_04
- [Canvas系列]Canvas绘制曲线之arcto_05
- Canvas 动态绘制简单的柱形图
- ..........
- ClassNotFoundException和NoClassDefFoundError的区别
- 深入java虚拟机---Java内存区域与内存溢出
- poj_2488
- 关于尊严项目的反思
- 【Android Canvas系列】使用canvas绘制简单的clock
- uva11100
- tar命令使用
- org.hibernate.MappingException: Could not determine type for: java.util.List, at table: user, for...
- HttpClient
- std::string::find() 和 std::string::npos
- c# 反射的使用
- pomelo服务器群消息变更的获知
- 进程间通信方式(IPC)