有这么一个需求:要求在应用中每个界面都有一个时钟显示时间,以秒更新。


自然而然,就想到了自定义View—以TextView+Handler方式倒是虽然可以实现,但难免累赘;
而时钟显示肯定要本身维护一个更新UI的线程,继承View固然是正确的,但不如继承SurfaceView来得更为直接—作为一个经常用来播放视频和展现游戏画面的控件,无疑是最佳选择。


很简单的东西,除了surfaceview的通常注意事项,额外注意三点即可:

  • 内容位置—行间距的处理
  • 适配处理—根据内容大小调整边界
  • 清屏刷新—最好使背景透明以便复用

代码如下:

public class DigitalClockView extends SurfaceView implements SurfaceHolder.Callback, Runnable {/*** 视图控制*/private SurfaceHolder mHolder;/*** 画布*/private Canvas mCanvas;/*** 线程开启或停止标志*/private boolean isRun;/*** 日期画笔*/private TextPaint mDatePaint;/*** 时间画笔*/private TextPaint mTimePaint;/*** 日期格式*/private String mDateFormat;/*** 时间格式*/private String mTimeFormat;/*** 日期文字大小*/private float mDateTextSize;/*** 时间文字大小*/private float mTimeTextSize;/*** 日期文字内容距边界大小*/private float mDateTopPadding;/*** 时间文字内容距日期文字内容大小*/private float mTimeTopPadding;public DigitalClockView(Context context) {this(context, null);}public DigitalClockView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DigitalClockView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);int dateTextColor = -1;int timeTextColor = -1;final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DigitalClockView);final int count = a.getIndexCount();for (int i = 0; i < count; i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.DigitalClockView_date_format:mDateFormat = a.getString(attr);break;case R.styleable.DigitalClockView_time_format:mTimeFormat = a.getString(attr);break;case R.styleable.DigitalClockView_date_text_size:mDateTextSize = a.getDimension(attr, 20);break;case R.styleable.DigitalClockView_time_text_size:mTimeTextSize = a.getDimension(attr, 20);break;case R.styleable.DigitalClockView_date_text_color:dateTextColor = a.getColor(attr, -1);break;case R.styleable.DigitalClockView_time_text_color:timeTextColor = a.getColor(attr, -1);break;}}// 文字画笔mDatePaint = new TextPaint();mTimePaint = new TextPaint();// 画笔是否抗锯齿mDatePaint.setAntiAlias(true);mTimePaint.setAntiAlias(true);// 文字居中mDatePaint.setTextAlign(Paint.Align.CENTER);mTimePaint.setTextAlign(Paint.Align.CENTER);// 文字颜色mDatePaint.setColor(dateTextColor);mTimePaint.setColor(timeTextColor);// 文字大小mDatePaint.setTextSize(mDateTextSize);mTimePaint.setTextSize(mTimeTextSize);// 文字绘制位置Paint.FontMetrics fontMetrics1 = mDatePaint.getFontMetrics();Paint.FontMetrics fontMetrics2 = mTimePaint.getFontMetrics();mDateTopPadding = Math.abs(fontMetrics1.top);mTimeTopPadding = fontMetrics1.bottom - fontMetrics1.top + Math.abs(fontMetrics2.ascent);// 获取控制mHolder = getHolder();mHolder.addCallback(this);// 背景透明this.setZOrderOnTop(true);this.getHolder().setFormat(PixelFormat.TRANSPARENT);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {isRun = true;new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//一般不必覆写}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {isRun = false;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int desiredWidth, desiredHeight;if (widthMode == MeasureSpec.EXACTLY) {desiredWidth = widthSize;} else {// 以文字宽度为适配int dateTextWidth = (int) mDatePaint.measureText(mDateFormat);int timeTextWidth = (int) mTimePaint.measureText(mTimeFormat);desiredWidth = Math.max(dateTextWidth, timeTextWidth);if (widthMode == MeasureSpec.AT_MOST) {desiredWidth = Math.min(widthSize, desiredWidth);}}if (heightMode == MeasureSpec.EXACTLY) {desiredHeight = heightSize;} else {// 以文字高度为适配Paint.FontMetrics fontMetrics1 = mDatePaint.getFontMetrics();Paint.FontMetrics fontMetrics2 = mTimePaint.getFontMetrics();desiredHeight = (int) (fontMetrics1.bottom - fontMetrics1.top + fontMetrics2.bottom - fontMetrics2.top);if (heightMode == MeasureSpec.AT_MOST) {desiredHeight = Math.min(heightSize, desiredHeight);}}setMeasuredDimension(desiredWidth, desiredHeight);}@Overridepublic void run() {long start, end;while (isRun) {start = System.currentTimeMillis();draw();end = System.currentTimeMillis();// 消除延时try {if (end - start < 1000) {Thread.sleep(1000 - (end - start));}} catch (InterruptedException e) {e.printStackTrace();}}}private void draw() {try {mCanvas = mHolder.lockCanvas();if (mCanvas != null) {// 刷屏,透明覆盖mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);// 绘制文字mCanvas.drawText(SysUtil.getDate(System.currentTimeMillis(), mDateFormat), mCanvas.getWidth() / 2,mDateTopPadding, mDatePaint);mCanvas.drawText(SysUtil.getDate(System.currentTimeMillis(), mTimeFormat), mCanvas.getWidth() / 2,mTimeTopPadding, mTimePaint);}} catch (Exception e) {e.printStackTrace();} finally {if (mCanvas != null) {mHolder.unlockCanvasAndPost(mCanvas);}}}

自定义属性attrs.xml,包括了时间格式、字体大小、字体颜色三种属性,在代码中读取设置即可:

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="DigitalClockView"><attr name="date_format" format="string|reference"/><attr name="time_format" format="string|reference"/><attr name="date_text_size" format="dimension|reference"/><attr name="time_text_size" format="dimension|reference"/><attr name="date_text_color" format="color|reference"/><attr name="time_text_color" format="color|reference"/></declare-styleable></resources>

最后是应用activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/darkviolet" ><com.xter.clock.view.DigitalClockView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"app:date_format="yyyy年MM月dd日"app:date_text_color="@color/white"app:date_text_size="@dimen/text_18"app:time_format="HH:mm:ss"app:time_text_color="@color/white"app:time_text_size="@dimen/text_34" /></RelativeLayout>

效果图:

源码:

https://github.com/ifmylove2011/digital_clock.git

自定义数字时钟DigitalClockView相关推荐

  1. java数字时钟代码,Android自定义数字时钟代码,android自定义时钟,package jp.t

    Android自定义数字时钟代码,android自定义时钟,package jp.tpackage jp.tsmsogn.digitalclock;import java.util.Calendar; ...

  2. 练习:数字时钟(Python 自定义类)

    Python 官网:https://www.python.org/ Free:大咖免费"圣经"教程< python 完全自学教程>,不仅仅是基础那么简单-- My CS ...

  3. android 数字时钟代码大全,Android自定义view实现数字时钟

    最近在项目中遇到了一个需要实时更新时间的需求,并且用的地方还是挺多的,无奈做了一个简单的view来时现这个数字时钟. 首先看一下效果,比较简单,就是显示时分秒. 实现思路比较简单,利用handler的 ...

  4. python定义一个类描述数字时钟_python自定义时钟类、定时任务类

    这是我使用python写的第一个类(也算是学习面向对象语言以来正式写的第一个解耦的类),记录下改进的过程. 分析需求 最初,因为使用time模块显示日期时,每次都要设置时间字符串的格式,挺麻烦,但还是 ...

  5. 电脑罗盘时钟代码_苹果电脑怎么设置数字时钟屏保 Word Clock for Mac安装教程

    [闽南网] Word Clock Mac版作为一款精美和酷炫的数字时钟屏保,目前受到了非常多的用户的欢迎和使用.word clock作为一款纯文字排版屏幕保护应用,让用户的电脑屏保瞬间变的" ...

  6. 简易数字时钟软件详细制作过程

    这是我自己用VS2010制作的简易数字时钟小软件,在制作过程中收获知识不少,希望和初学MFC编程的朋友分享一下. 一.其功能有一下三点: 1.打开软件后,其程序自动获取当前电脑系统的日期.时间和周次, ...

  7. 我的 iPhone XS Max 终于装上了这款高逼格数字时钟,优秀不优秀?!

    第一眼以为是 fliqlo,确认过眼神后才知道是...... 有朋友说这是一种美国乡村的感觉 ​惬意!有人说,對自己好一點,那是會跟你在一起最久的人.周末,郊外,一个人的午后时光,着实让我享受这样的时 ...

  8. Verilog数字系统设计——数字时钟(带暂停和任意位置位)

    verilog数字时钟设计 功能说明 问题分析及模块实现 模24计数器 模60计数器 模6计数器 模10计数器 模60计数器 数码管驱动电路 11位控制位说明 分频器 数字时钟 顶层文件实现 写在后面 ...

  9. 告别电子小白,8个优选DS1302数字时钟方案大合辑

    数字时钟是一个在主屏幕显示数字时间和日期的 android 桌面插件.是一款朴实简约的时钟 widget,能展示时间,触摸激活闹钟和日历,并且字体颜色都可以进行设置,界面看起来十分的简洁大方,有iPh ...

  10. Android Studio利用时钟控件AnalogClock显示模拟时钟以及TextClock显示数字时钟

    前言 利用时钟控件AnalogClock快速制作一个模拟时钟.利用TextClock显示数字时钟. 一.AnalogClock是什么? AnalogClock继承的是View,可重写OnDraw方法. ...

最新文章

  1. Node.js 究竟是什么?
  2. 无厘头的mysql故障排除
  3. 在Debian/Ubuntu上面安装升级nginx到最新版
  4. 基于simulink的QAM-WIMAX的系统仿真
  5. 基于区块链的健康链系统设计与实现(4)系统实现
  6. [转载] 深入剖析 redis 主从复制
  7. 放置奇兵 算法 月度活动 破碎时空记录 1-3关
  8. 都说Python库千千万,这几个你认识不?
  9. 编码方式_【每日一题】| 常见的编码方式之栅栏密码
  10. mysql where true_在MySQL中选择查询,检查字符串或在where子句中检查是否为true?
  11. Linux 发展历史
  12. 操作系统-存储器管理
  13. 航天有关的计算机知识,这些关于神舟十二上的电脑硬核小知识,你知道吗?
  14. JSP实用教程(2)——JSP语法
  15. OpenCV模板匹配方法原理
  16. Excel工作表保护的密码破解与清除...假装自己破解密码系列?
  17. Linux编程基础 5.2:消息队列
  18. 转载 基于MATLAB 进行图像分类
  19. 鸿蒙杀戮手机电脑版,鸿蒙杀戮单职业
  20. LPN管理中涉及到的LPN过多不能释放,导致在调拨环节零散LPN太多,如何解决该问题?

热门文章

  1. 阿里P9技术:我来聊聊百万年薪
  2. isupper()函数
  3. Android6.0 源码修改之屏蔽系统短信功能和来电功能
  4. mysql时间转换格式
  5. 【机器学习】注意力机制
  6. 解密加油优惠打折券的制作过程
  7. GeoTrans2.4.1 用户手册 之 (六)笔记
  8. 自己处理域名、主机备案流程 + 公网安备流程,总共耗时半个月左右
  9. 大数据行业发展前景及岗位方向如何?
  10. wps无法使用F4重复上一步操作的解决方法