Android实现简单时钟View的方法
发布时间 - 2026-01-11 02:53:06 点击率:次通过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
# 时钟
# View
# Android获取设备CPU核数、时钟频率以及内存大小的方法
# Android多功能时钟开发案例(实战篇)
# android实现widget时钟示例分享
# Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果
# Android多功能时钟开发案例(基础篇)
# android高仿小米时钟(使用Camera和Matrix实现3D效果)
# Android自定义动态壁纸开发(时钟)
# Android编程基于自定义控件实现时钟功能的方法
# Android仿小米时钟效果
# Android自定义View实现时钟功能
# 顺时针
# 完成后
# 移到
# 朝上
# 是在
# 后将
# 是一个非常
# 时用
# 大家多多
# mHeight
# mRadius
# mTickLengthSecond
# mWidth
# mPaintScaleShort
# mPaintOutline
# Canvas
# mPaintScaleLong
# private
# float
# ClockView
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】
Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】
深圳网站制作的公司有哪些,dido官方网站?
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中
宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程
Python自然语言搜索引擎项目教程_倒排索引查询优化案例
企业网站制作这些问题要关注
成都品牌网站制作公司,成都营业执照年报网上怎么办理?
大连 网站制作,大连天途有线官网?
iOS发送验证码倒计时应用
JavaScript如何实现音频处理_Web Audio API如何工作?
Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】
Laravel怎么调用外部API_Laravel Http Client客户端使用
Laravel N+1查询问题如何解决_Eloquent预加载(Eager Loading)优化数据库查询
怎样使用JSON进行数据交换_它有什么限制
google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤
Laravel如何实现数据库事务?(DB Facade示例)
HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】
javascript基本数据类型及类型检测常用方法小结
香港服务器建站指南:免备案优势与SEO优化技巧全解析
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
如何在腾讯云服务器快速搭建个人网站?
Laravel如何配置Horizon来管理队列?(安装和使用)
Laravel表单请求验证类怎么用_Laravel Form Request分离验证逻辑教程
iOS验证手机号的正则表达式
Android okhttputils现在进度显示实例代码
HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】
惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?
如何选择可靠的免备案建站服务器?
JS碰撞运动实现方法详解
如何在IIS中新建站点并配置端口与IP地址?
关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)
如何利用DOS批处理实现定时关机操作详解
Win11怎么设置虚拟桌面 Win11新建多桌面切换操作【技巧】
Python3.6正式版新特性预览
如何选择PHP开源工具快速搭建网站?
php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】
php在windows下怎么调试_phpwindows环境调试操作说明【操作】
电商网站制作价格怎么算,网上拍卖流程以及规则?
Laravel怎么发送邮件_Laravel Mail类SMTP配置教程
如何在阿里云ECS服务器部署织梦CMS网站?
Python文件流缓冲机制_IO性能解析【教程】
Laravel如何处理异常和错误?(Handler示例)
Laravel如何编写单元测试和功能测试?(PHPUnit示例)
HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】
Laravel观察者模式如何使用_Laravel Model Observer配置
如何在香港服务器上快速搭建免备案网站?
android nfc常用标签读取总结
手机怎么制作网站教程步骤,手机怎么做自己的网页链接?

