监狱培欲,智能手机加盟,秦琼传
通过canvas的平移与旋转简化绘图逻辑是一个非常有用的技巧,下面的时钟view就是利用这个方法完成的,省去了使用三角函数计算坐标的麻烦。
package com.example.swt369.simpleclock; import android.content.context; import android.graphics.canvas; import android.graphics.paint; import android.support.annotation.nullable; import android.util.attributeset; import android.view.view; import android.view.viewtreeobserver; import android.widget.toast; import java.util.calendar; /** * created by swt369 on 2017/8/20. */ public class clockview extends view { //时钟各个部件的长度 private float mscalelengthlong; private float mscalelengthshort; private float mticklengthhour; private float mticklengthminute; private float mticklengthsecond; //view的宽和高 private float mwidth; private float mheight; //时钟半径 private float mradius; //绘制各部件时用的paint private paint mpaintscalelong; private paint mpaintscaleshort; private paint mpaintoutline; private paint mpaintnum; private paint mpainttickhour; private paint mpainttickminute; private paint mpaintticksecond; private viewtreeobserver.onpredrawlistener onpredrawlistener; public clockview(final context context, @nullable attributeset attrs) { super(context, attrs); onpredrawlistener = new viewtreeobserver.onpredrawlistener() { //获取view宽高并计算各个部件的长度 @override public boolean onpredraw() { mwidth = getmeasuredwidth(); mheight = getmeasuredheight(); mradius = math.min(mwidth,mheight) / 2 * 0.95f; mscalelengthlong = mradius * 0.1f; mscalelengthshort = mradius * 0.05f; mticklengthhour = mradius * 0.3f; mticklengthminute = mradius * 0.45f; mticklengthsecond = mradius * 0.6f; return true; } }; getviewtreeobserver().addonpredrawlistener(onpredrawlistener); //点击显示具体时间 setonclicklistener(new onclicklistener() { @override public void onclick(view v) { calendar calendar = calendar.getinstance(); string time = string.format("当前时间:%02d:%02d:%02d", calendar.get(calendar.hour_of_day),calendar.get(calendar.minute),calendar.get(calendar.second)); toast.maketext(context,time, toast.length_short).show(); } }); //初始化所有paint对象 initializepaints(); } @override protected void ondraw(canvas canvas) { if(mwidth == 0 || mheight == 0){ return; } if(onpredrawlistener != null){ getviewtreeobserver().removeonpredrawlistener(onpredrawlistener); onpredrawlistener = null; } //绘制时钟 drawclock(canvas); //一秒后重绘 postinvalidatedelayed(1000); } private void drawclock(canvas canvas) { //保存原始状态 canvas.save(); //将坐标系原点移到中心,并逆时针旋转90度。完成后x轴朝上。 canvas.translate(mwidth / 2,mheight / 2); canvas.rotate(-90); //画外围轮廓 canvas.drawcircle(0,0,mradius, mpaintoutline); //画刻度 for(int i = 0 ; i < 12 ; i++){ string num = string.valueof(i == 0 ? 12 : i); if(i % 3 == 0){ canvas.drawline(mradius,0,mradius - mscalelengthlong,0, mpaintscalelong); }else { canvas.drawline(mradius,0,mradius - mscalelengthshort,0, mpaintscaleshort); } canvas.drawtext(num,mradius - mscalelengthlong - mpaintnum.measuretext(num) * 2,0, mpaintnum); //顺时针旋转30度 canvas.rotate(30); } calendar calendar = calendar.getinstance(); //画时针 int hour = calendar.get(calendar.hour); canvas.save(); canvas.rotate(hour * 30); canvas.drawline(0,0,mticklengthhour,0,mpainttickhour); canvas.restore(); //画分针 int minute = calendar.get(calendar.minute); canvas.save(); canvas.rotate(minute * 6); canvas.drawline(0,0,mticklengthminute,0,mpainttickminute); canvas.restore(); //画秒针 int second = calendar.get(calendar.second); canvas.save(); canvas.rotate(second * 6); canvas.drawline(0,0,mticklengthsecond,0,mpaintticksecond); canvas.restore(); //恢复原始状态 canvas.restore(); } private void initializepaints(){ mpaintscalelong = new paint(); mpaintscalelong.setantialias(true); mpaintscalelong.setstrokewidth(5); mpaintscaleshort = new paint(); mpaintscaleshort.setantialias(true); mpaintscaleshort.setstrokewidth(3); mpaintoutline = new paint(); mpaintoutline.setstyle(paint.style.stroke); mpaintoutline.setantialias(true); mpaintoutline.setstrokewidth(5); mpaintnum = new paint(); mpaintnum.settextsize(30); mpainttickhour = new paint(); mpainttickhour.setantialias(true); mpainttickhour.setstrokewidth(6); mpainttickminute = new paint(); mpainttickminute.setantialias(true); mpainttickminute.setstrokewidth(4); mpaintticksecond = new paint(); mpaintticksecond.setantialias(true); mpaintticksecond.setstrokewidth(2); } }
代码注释已经比较详细了,下面把比较重要的部分再说明一下:
//保存原始状态 canvas.save(); //省略中间部分... //恢复原始状态 canvas.restore();
在绘图开始时调用canvas.save(),可以保存下未经任何平移、旋转操作的原始画布状态。在所有绘图工作完成后调用canvas.restore(),可以恢复到上一次保存的状态(类似进出栈的感觉)。
//将坐标系原点移到中心,并逆时针旋转90度。完成后x轴朝上。 canvas.translate(mwidth / 2,mheight / 2); canvas.rotate(-90);
画布的平移与旋转可能比较抽象,可以想象成坐标系的平移与旋转。调用canvas.translate(dx,dy)相当于将坐标原点向x,y方向移动了dx,dy的距离,调用canvas.rotate(degree)相当于坐标系顺时针旋转了degree°。
//画刻度 for(int i = 0 ; i < 12 ; i++){ string num = string.valueof(i == 0 ? 12 : i); if(i % 3 == 0){ canvas.drawline(mradius,0,mradius - mscalelengthlong,0, mpaintscalelong); }else { canvas.drawline(mradius,0,mradius - mscalelengthshort,0, mpaintscaleshort); } canvas.drawtext(num,mradius - mscalelengthlong - mpaintnum.measuretext(num) * 2,0, mpaintnum); //顺时针旋转30度 canvas.rotate(30); }
根据i值决定是画大刻度(90°的倍数)还是小刻度。每次画完一条之后将坐标系顺时针旋转30°,这样保证每次画的刻度线的坐标不变。
//一秒后重绘 postinvalidatedelayed(1000);
作用是在1000ms(1s)后再次执行view的draw流程,产生指针运动的效果。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Android apk 项目一键打包并上传到蒲公英的实现方法
Android 自定义LineLayout实现满屏任意拖动功能的示例代码
android 限制某个操作每天只能操作指定的次数(示例代码详解)
Android 集成 google 登录并获取性别等隐私信息的实现代码
网友评论