Android自定义控件实现时钟效果
程序员文章站
2022-07-05 19:35:13
在学习安卓群英传自定义控件章节的时候,有一个例子是绘制时钟,在实现了书上的例子后就想看这个时钟能不能动起来。
这里选择延迟一秒发送消息重绘view来实现的动画,对外提供了开启时钟,关...
在学习安卓群英传自定义控件章节的时候,有一个例子是绘制时钟,在实现了书上的例子后就想看这个时钟能不能动起来。
这里选择延迟一秒发送消息重绘view来实现的动画,对外提供了开启时钟,关闭时钟的方法,当activity执行onresume方法的时候,执行startclock()方法,当移除view或activity执行onstop方法的时候可以执行stopclock()方法。
首先根据view的宽高来确定圆心的位置,并画出一个圆。再通过view高度的一半减去圆的半径,确定刻度的起始位置,选择刻度的长度并绘制出来。然后再刻度下方绘制出数字。最终将画布进行旋转,时钟总共有60个刻度,循环旋转,每次旋转6度即可。
最后是绘制指针,通过计算算出指针对应每个刻度的x,y坐标并绘制直线。
代码实现
自定义控件的代码:
public class clockview extends view{ private paint circlepaint,dialpaint,numberpaint; //view 的宽高 private float mwidth,mheight; //圆的半径 private float circleradius; //圆心x,y坐标 private float circlex,circley; private int second,minute; private double hour; private handler handler = new handler(looper.getmainlooper()){ @override public void handlemessage(message msg) { super.handlemessage(msg); if(msg.what==0){ invalidate(); } } }; public clockview(context context, attributeset attrs) { super(context, attrs); initpaint(); } private void initpaint(){ //刻盘圆,小时刻度,时针和分针的画笔 circlepaint = new paint(paint.anti_alias_flag); circlepaint.setcolor(color.black); circlepaint.setstyle(paint.style.stroke); circlepaint.setstrokewidth(10); //分钟刻度的画笔 dialpaint = new paint(paint.anti_alias_flag); dialpaint.setcolor(color.black); dialpaint.setstrokewidth(5); //数字的画笔 numberpaint = new paint(paint.anti_alias_flag); numberpaint.setcolor(color.black); numberpaint.setstrokewidth(5); numberpaint.settextsize(30); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); mwidth = getmeasuredwidth(); mheight = getmeasuredheight(); if(mwidth<mheight){ //圆的半径为view的宽度的一半再减9,防止贴边 circleradius = mwidth/2-9; circlex = mwidth/2; circley = mheight/2; } else{ circleradius = mheight/2-9; circlex = mwidth/2; circley = mheight/2; } } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); settimes(); drawcirclepoint(canvas); drawcircle(canvas); drawdial(canvas); drawpointer(canvas); } /**圆心 * @param canvas */ private void drawcirclepoint(canvas canvas){ canvas.drawcircle(circlex,circley,5,circlepaint); } private void drawcircle(canvas canvas){ canvas.drawcircle(circlex,circley,circleradius,circlepaint); } /**画刻度及时间 * @param canvas */ private void drawdial(canvas canvas){ //时钟用长一点的刻度,画笔用画圆的画笔 point hourstartpoint = new point(circlex,circley-circleradius); point hourendpoint = new point(circlex,circley-circleradius+40); //分钟的刻度要稍微短一些,画笔用画圆的画笔 point startpoint2 = new point(circlex,circley-circleradius); point endpoint2 = new point(circlex,circley-circleradius+10); //开始画刻度和数字,总共60个刻度,12个时钟刻度,被5整除画一个时钟刻度,被其余的为分针刻度 string clocknumber; for(int i=0;i<60;i++){ if(i%5==0){ if(i==0){ clocknumber = "12"; } else{ clocknumber = string.valueof(i/5); } //时针刻度 canvas.drawline(hourstartpoint.getx(),hourstartpoint.gety(),hourendpoint.getx(),hourendpoint.gety(),circlepaint); //画数字,需在时针刻度末端加30 canvas.drawtext(clocknumber,circlex-numberpaint.measuretext(clocknumber)/2,hourendpoint.gety()+30,numberpaint); } else{ //画分针刻度 canvas.drawline(startpoint2.getx(),startpoint2.gety(),endpoint2.getx(),endpoint2.gety(),circlepaint); } //画布旋转6度 canvas.rotate(360/60,circlex,circley); } } /**画指针 * x点坐标 cos(弧度)*r * y点坐标 sin(弧度)*r * toradians将角度转成弧度 * 安卓坐标系与数学坐标系不同的地方是x轴是相反的,所以为了调整方向,需要将角度+270度 * @param canvas */ private void drawpointer(canvas canvas){ canvas.translate(circlex,circley); float hourx = (float) math.cos(math.toradians(hour*30+270))*circleradius*0.5f; float houry = (float) math.sin(math.toradians(hour*30+270))*circleradius*0.5f; float minutex = (float) math.cos(math.toradians(minute*6+270))*circleradius*0.8f; float minutey = (float) math.sin(math.toradians(minute*6+270))*circleradius*0.8f; float secondx = (float) math.cos(math.toradians(second*6+270))*circleradius*0.8f; float secondy = (float) math.sin(math.toradians(second*6+270))*circleradius*0.8f; canvas.drawline(0,0,hourx,houry,circlepaint); canvas.drawline(0,0,minutex,minutey,circlepaint); canvas.drawline(0,0,secondx,secondy,dialpaint); //一秒重绘一次 handler.sendemptymessagedelayed(0,1000); } public void startclock(){ settimes(); invalidate(); } private void settimes(){ date date = new date(); calendar calendar = calendar.getinstance(); calendar.settime(date); second = gettimes(date,calendar.second); minute = gettimes(date,calendar.minute); hour = gettimes(date,calendar.hour)+minute/12*0.2; } private int gettimes(date date,int calendarfield){ calendar calendar = calendar.getinstance(); calendar.settime(date); return calendar.get(calendarfield); } public void stopclock(){ handler.removemessages(0); } }
public class point {
private float x;
private float y;
public point(float x, float y) { this.x = x; this.y = y; } public float getx() { return x; } public void setx(float x) { this.x = x; } public float gety() { return y; } public void sety(float y) { this.y = y; }
acitivity:
public class clockactivity extends activity{ private clockview clockview; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.clock_layout); clockview = (clockview) findviewbyid(r.id.clock); } @override protected void onresume() { super.onresume(); clockview.startclock(); } @override protected void onstop() { super.onstop(); clockview.stopclock(); } }
xml布局:
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:gravity="center" android:layout_height="match_parent"> <com.example.customview.view.clockview android:layout_width="match_parent" android:id="@+id/clock" android:layout_height="match_parent" /> </linearlayout>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: ES6新增的数组知识实例小结