通过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闹钟功能,包括了简单实现Android闹钟功能的使用技巧和注意事项,需要的朋友参考一下 闹钟的简单实现,只有显示时间和设置闹钟。 AlarmView TimeView AlarmReceiver MainActivity PlayAlarmAty 运行效果图 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
本文向大家介绍Qt实现简易时钟,包括了Qt实现简易时钟的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Qt实现简易时钟展示的具体代码,供大家参考,具体内容如下 一、效果展示 简单实现时钟(圆盘+QLCDNumber),大小刻度,数字等。 二、实现 .pro .h .cpp 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
本文向大家介绍简单实现Android闹钟程序 附源码,包括了简单实现Android闹钟程序 附源码的使用技巧和注意事项,需要的朋友参考一下 这个应用实现了简单的闹钟功能,关闭程序的状态中也可以进行闹钟的提醒。 这里遗留了一个问题: 如果我通过应用本身关闭程序,是可以实现我上述所说的功能,但是如果我在手机进程管理中实现应用程序的关闭操作,这个提醒就不起作用了,我很疑惑的是,我通过应用程序本身关闭了后
本文向大家介绍教你3分钟了解Android 简易时间轴的实现方法,包括了教你3分钟了解Android 简易时间轴的实现方法的使用技巧和注意事项,需要的朋友参考一下 一.有段时间没更了,因为一直在思索,应该写点什么,真的是无比纠结。这一回,就给大家分享一款简便好用的,小编自制的土晾时间轴。 附上XML预览图: 效果图 注:小黄鸭不是效果哈,是为了保护个人隐私P上去的: 1.新建一个自定义控件: XM
本文向大家介绍Android简单实现屏幕下方Tab菜单的方法,包括了Android简单实现屏幕下方Tab菜单的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Android简单实现屏幕下方Tab菜单的方法。分享给大家供大家参考,具体如下: 看到很多热门的Android程序(如:新浪微博、腾讯微博、京东商城、淘宝、当当等等)使用选项卡风格作为程序界面的主框架结构,而Android的选项卡
本文向大家介绍Android实现简易闹钟功能,包括了Android实现简易闹钟功能的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Android通过广播来实现闹钟的具体代码,供大家参考,具体内容如下 1.创建广播接收RepeatingAlarm.java 2.广播在Manifest.xml中配置: 3.通过代码设置一个闹钟 4.通过代码取消一个闹钟: 5.闹钟响是弹出的对化框并播放音