Android -- [SelfView] 自定义圆盘指针时钟

Android – [SelfView] 自定义圆盘指针时钟

ps:简约圆盘指针时钟,颜色可调、自由搭配;支持阿拉伯数字、罗马数字刻度显示;
效果图

在这里插入图片描述

使用:
<!-- 自定义属性参考 attrs.xml 文件 -->
<com.nepalese.harinetest.player.VirgoCircleClockandroid:id="@+id/circleclock"android:layout_width="300dp"android:layout_height="300dp"app:paddingFrame="10dp"app:strokeSize="5dp"app:offsetMark="-1dp"app:offsetText="-1dp"app:rSmall="5px"app:rBig="8px"app:needBg="true"app:frameColor="@color/colorBlack30"app:bgColor="@color/colorEye"app:markColor1="@color/black"app:markColor2="@color/colorWhite"app:textColor="@color/black"app:txtSize="18sp"app:displayType="type_num"/>
private VirgoCircleClock circleClock;//使用
circleClock = findViewById(R.id.circleclock);
circleClock.startPlay();//注销
if (circleClock != null) {circleClock.releaseView();
}
码源:
1. attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="VirgoCircleClock"><!--是否绘制背景 默认透明--><attr name="needBg" format="boolean" /><!--背景颜色 默认白色--><attr name="bgColor" format="color|reference"/><!--边框颜色 默认黑色--><attr name="frameColor" format="color|reference"/><!--小刻度颜色--><attr name="markColor1" format="color|reference"/><!--大刻度颜色--><attr name="markColor2" format="color|reference"/><!--文字颜色 & 时针、分针颜色--><attr name="textColor" format="color|reference"/><!--秒针颜色--><attr name="secondColor" format="color|reference"/><!--大、小刻度点半径--><attr name="rBig" format="dimension|reference"/><attr name="rSmall" format="dimension|reference"/><attr name="offsetMark" format="dimension|reference"/><attr name="offsetText" format="dimension|reference"/><!--数字类型--><attr name="displayType" format="integer"><enum name="type_num" value="1"/><enum name="type_roma" value="2"/></attr><!--内缩间距--><attr name="paddingFrame" format="dimension|reference"/><!--文字大小--><attr name="txtSize" format="dimension|reference"/><!--边框厚度--><attr name="strokeSize" format="dimension|reference"/></declare-styleable>
</resources>
2. VirgoCircleClock.java
package com.nepalese.harinetest.player;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;import androidx.annotation.Nullable;import com.nepalese.harinetest.R;import java.util.Calendar;public class VirgoCircleClock extends View {private static final String TAG = "VirgoCircleClock";private static final int DEF_RADIUS_BIG = 3;private static final int DEF_RADIUS_SMALL = 2;private static final int DEF_OFF_MARK = 2;//刻度与边框间距private static final int DEF_OFF_TEXT = 3;//数字与边框间距private static final int TYPE_NUM = 1;//阿拉伯数字private static final int TYPE_ROMA = 2;//罗马数字private static final int DEF_PADDING = 15;//内缩间距private static final float DEF_SIZE_TEXT = 18f;//数字大小private static final float DEF_FRAME_STROKE = 5f;//边框厚度private static final float RATE_HOUR = 0.5f;//时针与半径比例private static final float RATE_HOUR_TAIL = 0.05f;//时针尾巴与半径比例private static final float RATE_HOUR_WIDTH = 70f;//时针尾巴与半径比private static final float RATE_MINUTE = 0.6f;//分针与半径比例private static final float RATE_MINUTE_TAIL = 0.08f;//分针尾巴与半径比例private static final float RATE_MINUTE_WIDTH = 120f;//分针尾巴与半径比private static final float RATE_SECOND = 0.7f;//秒针与半径比例private static final float RATE_SECOND_TAIL = 0.1f;//秒针尾巴与半径比例private static final float RATE_SECOND_WIDTH = 240f;//秒针宽度与半径比private Paint paintMain;//刻度+指针private Paint paintFrame;//外环边框private Calendar calendar;private boolean needBg;//是否绘制背景 默认透明private int bgColor;//背景颜色 默认白色private int frameColor;//边框颜色private int markColor1;//小刻度颜色private int markColor2;//大刻度颜色private int textColor;//文字颜色 & 时针、分针颜色private int secondColor;//秒针颜色private int radiusBig, radiusSmall;//大、小刻度点半径private int offMark, offText;private int markY, txtY;private int displayStyle;//数字类型private int padding;//内缩间距private int radius;//表盘半径private int hours, minutes, seconds;//当前时分秒private int centerX, centerY;//表盘中心坐标private float textSize;//文字大小private float strokeSize;//边框厚度public VirgoCircleClock(Context context) {this(context, null);}public VirgoCircleClock(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VirgoCircleClock(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}private void init(Context context, AttributeSet attrs) {TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VirgoCircleClock);needBg = typedArray.getBoolean(R.styleable.VirgoCircleClock_needBg, false);bgColor = typedArray.getColor(R.styleable.VirgoCircleClock_bgColor, Color.WHITE);frameColor = typedArray.getColor(R.styleable.VirgoCircleClock_frameColor, Color.BLACK);markColor1 = typedArray.getColor(R.styleable.VirgoCircleClock_markColor1, Color.BLACK);markColor2 = typedArray.getColor(R.styleable.VirgoCircleClock_markColor2, Color.DKGRAY);textColor = typedArray.getColor(R.styleable.VirgoCircleClock_textColor, Color.BLACK);secondColor = typedArray.getColor(R.styleable.VirgoCircleClock_secondColor, Color.RED);radiusBig = typedArray.getDimensionPixelSize(R.styleable.VirgoCircleClock_rBig, DEF_RADIUS_BIG);radiusSmall = typedArray.getDimensionPixelSize(R.styleable.VirgoCircleClock_rSmall, DEF_RADIUS_SMALL);offMark = typedArray.getDimensionPixelSize(R.styleable.VirgoCircleClock_offsetMark, DEF_OFF_MARK);offText = typedArray.getDimensionPixelSize(R.styleable.VirgoCircleClock_offsetText, DEF_OFF_TEXT);displayStyle = typedArray.getInteger(R.styleable.VirgoCircleClock_displayType, TYPE_NUM);textSize = typedArray.getDimension(R.styleable.VirgoCircleClock_txtSize, DEF_SIZE_TEXT);strokeSize = typedArray.getDimension(R.styleable.VirgoCircleClock_strokeSize, DEF_FRAME_STROKE);padding = typedArray.getDimensionPixelSize(R.styleable.VirgoCircleClock_paddingFrame, DEF_PADDING);initData();}/*** 设置|更改布局时调用** @param width  容器宽* @param height 容器高*/public void initLayout(int width, int height) {Log.d(TAG, "initLayout: " + width + " - " + height);//取小//表盘直径int diameter = Math.min(width, height);//半径radius = (int) ((diameter - padding - strokeSize) / 2);//圆心centerX = diameter / 2;centerY = diameter / 2;markY = (int) (padding + strokeSize + offMark);txtY = markY + radiusBig * 2 + offText;}private void initData() {paintMain = new Paint();paintMain.setAntiAlias(true);paintMain.setStyle(Paint.Style.FILL);paintFrame = new Paint();paintFrame.setAntiAlias(true);paintFrame.setStyle(Paint.Style.STROKE);paintFrame.setStrokeWidth(strokeSize);calendar = Calendar.getInstance();}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (w > 0 && h > 0) {initLayout(w, h);}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (radius < 1) {return;}getTimes();//画表盘drawPlate(canvas);//画指针drawPointHour(canvas);drawPointMinutes(canvas);drawPointSeconds(canvas);}//刷新时间private void getTimes() {calendar.setTimeInMillis(System.currentTimeMillis());hours = calendar.get(Calendar.HOUR_OF_DAY);minutes = calendar.get(Calendar.MINUTE);seconds = calendar.get(Calendar.SECOND);}//画表盘private void drawPlate(Canvas canvas) {//背景if(needBg){paintMain.setColor(bgColor);canvas.drawCircle(centerX, centerY, radius, paintMain);}//边框paintFrame.setColor(frameColor);canvas.drawCircle(centerX, centerY, radius, paintFrame);canvas.save();//刻度for (int i = 0; i < 60; i++) {if (i % 5 == 0) {//大刻度paintMain.setColor(markColor1);canvas.drawCircle(centerX - radiusBig / 2f, markY, radiusBig, paintMain);} else {paintMain.setColor(markColor2);canvas.drawCircle(centerX - radiusSmall / 2f, markY, radiusSmall, paintMain);}canvas.rotate(6, centerX, centerY);}canvas.restore();paintMain.setColor(textColor);paintMain.setTextSize(textSize);//数字for (int i = 1; i <= 12; i++) {//计算每个数字所在位置的角度double radians = Math.toRadians(30 * i); //将角度转换为弧度,以便计算正弦值和余弦值String hourText;if (displayStyle == TYPE_ROMA) {hourText = getHoursGreece(i);} else {hourText = String.valueOf(i);}Rect rect = new Rect(); //获取数字的宽度和高度paintMain.getTextBounds(hourText, 0, hourText.length(), rect);int textWidth = rect.width();int textHeight = rect.height();canvas.drawText(hourText,(float) (centerX + (radius - txtY) * Math.sin(radians) - textWidth / 2),(float) (centerY - (radius - txtY) * Math.cos(radians) + textHeight / 2),paintMain); //通过计算出来的坐标进行数字的绘制}}private void drawPointHour(Canvas canvas) {//画时针drawPoint(canvas, 360 / 12 * hours + (30 * minutes / 60), RATE_HOUR, RATE_HOUR_TAIL, RATE_HOUR_WIDTH);}private void drawPointMinutes(Canvas canvas) {//画分针drawPoint(canvas, 360 / 60 * minutes + (6 * seconds / 60), RATE_MINUTE, RATE_MINUTE_TAIL, RATE_MINUTE_WIDTH);}private void drawPointSeconds(Canvas canvas) {paintMain.setColor(secondColor);//画秒针drawPoint(canvas, 360 / 60 * seconds, RATE_SECOND, RATE_SECOND_TAIL, RATE_SECOND_WIDTH);}/*** 画指针** @param canvas    画布* @param degree    指针走过角度* @param rateLen   正向长度与半径比* @param rateTail  尾部长度与半径比* @param rateWidth 宽度占半径比*/private void drawPoint(Canvas canvas, int degree, float rateLen, float rateTail, float rateWidth) {//角度的计算由当前的小时占用的角度加上分针走过的百分比占用的角度之和double radians = Math.toRadians(degree);//时针的起点为圆的中点//通过三角函数计算时针终点的位置,时针最短,取长度的0.5倍int endX = (int) (centerX + radius * Math.cos(radians) * rateLen); //计算直线终点x坐标int endY = (int) (centerY + radius * Math.sin(radians) * rateLen); //计算直线终点y坐标canvas.save();paintMain.setStrokeWidth(radius / rateWidth);//初始角度是0,应该从12点钟开始算,所以要逆时针旋转90度canvas.rotate((-90), centerX, centerY); // 因为角度是从x轴为0度开始计算的,所以要逆时针旋转90度,将开始的角度调整到与y轴重合canvas.drawLine(centerX, centerY, endX, endY, paintMain); //根据起始坐标绘制时针radians = Math.toRadians(degree - 180); //时针旋转180度,绘制小尾巴endX = (int) (centerX + radius * Math.cos(radians) * rateTail);endY = (int) (centerY + radius * Math.sin(radians) * rateTail);canvas.drawLine(centerX, centerY, endX, endY, paintMain);canvas.restore();}private String getHoursGreece(int i) {switch (i) {case 1:return "I";case 2:return "II";case 3:return "III";case 4:return "IV";case 5:return "V";case 6:return "VI";case 7:return "VII";case 8:return "VIII";case 9:return "IX";case 10:return "X";case 11:return "XI";case 12:default:return "XII";}}//===================================================private final int MSG_UPDATE_TIME = 1;private final Handler handler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {if (msg.what == MSG_UPDATE_TIME) {invalidate();startTask();}return false;}});private void startTask() {handler.removeMessages(MSG_UPDATE_TIME);handler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, 1000L);}private void pauseTask() {removeMsg();}private void stopTask() {removeMsg();}private void removeMsg() {handler.removeMessages(MSG_UPDATE_TIME);}//==========================api========================================public void startPlay() {startTask();}public void pausePlay() {pauseTask();}public void continuePlay() {startTask();}public void releaseView() {stopTask();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58754.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

边缘计算【智能+安全检测】系列教程--agx orin解决RTC时间问题

因为是离线运行&#xff0c;首要问题是时间不准确&#xff0c;就在主板上加装了纽扣电池&#xff0c;但是会有一系列问题&#xff0c;比如无法将RTC时间回写到系统时间&#xff0c;或者无法将系统时间写到RTC中等等一些列问题。为解决这些问题&#xff0c;一劳永逸的方式&#…

智能家居10G雷达感应开关模块,飞睿智能uA级别低功耗、超高灵敏度,瞬间响应快

在当今科技飞速发展的时代&#xff0c;智能家居已经逐渐成为人们生活中不可或缺的一部分。从智能灯光控制到智能家电的联动&#xff0c;每一个细节都在为我们的生活带来便利和舒适。而在众多智能家居产品中&#xff0c;10G 雷达感应开关模块以其独特的优势&#xff0c;正逐渐成…

【源码+文档】基于SpringBoot+Vue旅游网站系统【提供源码+答辩PPT+参考文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

Python Matplotlib:基本图表绘制指南

Python Matplotlib&#xff1a;基本图表绘制指南 Matplotlib 是 Python 中一个非常流行的绘图库&#xff0c;它以简单易用和功能丰富而闻名&#xff0c;适合各种场景的数据可视化需求。在数据分析和数据科学领域&#xff0c;Matplotlib 是我们展示数据的有力工具。本文将详细讲…

开源库 FloatingActionButton

开源库FloatingActionButton Github:https://github.com/Clans/FloatingActionButton 这个库是在前面这个库android-floating-action-button的基础上修改的&#xff0c;增加了一些更强大和实用的特性。 特性&#xff1a; Android 5.0 以上点击会有水波纹效果 可以选择自定义…

【Hello World 】

【Hello World 】! C语言实现C实现Java实现Python实现 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 几乎每一个程序员都是从Hello World!开始自己的程序人生&#xff0c;作为一个初学编程的小朋友&#xff0c;也需要先编程来输出Hello Wo…

从实验室到生活:超分子水凝胶湿电发电机的应用之路

大家好&#xff01;今天来了解一种新型的绿色湿电发电机&#xff08;MEG&#xff09;——《Green moisture-electric generator based on supramolecular hydrogel with tens of milliamp electricity toward practical applications》发表于《nature communications》&#xf…

零基础学习Java AI Spring AI

零基础学习Java AI Spring AI 随着人工智能&#xff08;AI&#xff09;技术的超速发展&#xff0c;越来越多的开发者开始将目光投向AI应用的开发。作为一名java程序员&#xff0c;如果不转型就会面临淘汰&#xff0c;程序员的世界就是这么的实现。 现在&#xff0c;市面上大多…

【周末推荐】Windows无缝连接iPhone

关注“ONE生产力”&#xff0c;获取更多精彩推荐&#xff01; 又到了周末推荐时间了&#xff0c;今天我们介绍一个Windows内置的功能&#xff0c;能够帮助大家将自己的电脑和iPhone连接在一起。 很多用Windows的小伙伴羡慕macOS可以和iPhone无缝连接&#xff0c;轻松阅读和回…

OV5640摄像模组从入门到精通(1)

本文内容参考&#xff1a; 《OmniVision OV5640 datasheet》 《OV5640 Camera Module — Software Application Notes》 OV5640学习_ov5640手册-CSDN博客 OV5640手册解读-CSDN博客 【FPGA】摄像头模块OV5640-CSDN博客 Camera开发-OV5640(MIPI)-CSDN博客 特此致谢&#x…

el-table type=“selection“换页多选数据丢失的解决办法

element里有一个 reserve-selection属性 设置以后就可以保留之前选中的选项&#xff0c;但还要设置row-key 代码如下&#xff1a; <el-tableref"mytable":data"HostRows"borderv-loading"loading"element-loading-text"正在加载中...&q…

CPU算法分析LiteAIServer视频智能分析平台视频诊断对比度检测:提升视频监控质量的关键技术

在现代安防、工业生产、智能家居等领域&#xff0c;视频监控系统扮演着至关重要的角色。然而&#xff0c;视频质量的好坏直接影响到监控效果&#xff0c;而对比度作为衡量图像质量的重要指标之一&#xff0c;对于视频内容的清晰度和细节表现至关重要。为了应对这一挑战&#xf…

双向 Type-C 转 DP 线:高清视频输出的灵活解决方案

在当今数字化生活中&#xff0c;人们对高效能和高清晰度的需求日益增长。双向 Type-C 转 DP 线应运而生&#xff0c;它以其灵活便捷的特点&#xff0c;为用户提供了一种高清视频输出的解决方案。本文将详细介绍双向 Type-C 转 DP 线的技术原理、适用设备、性能参数以及市场选择…

萤石设备视频接入平台EasyCVR私有化部署视频平台高速公路视频上云的高效解决方案

经济的迅猛发展带来了高速公路使用频率的激增&#xff0c;其封闭、立交和高速的特性变得更加显著。然而&#xff0c;传统的人工巡查方式已不足以应对当前高速公路的监控挑战&#xff0c;监控盲点和响应速度慢成为突出问题。比如&#xff0c;非法占用紧急车道的情况屡见不鲜&…

Spring Boot在信息学科平台建设中的应用

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于保密信息学科平台系统的相关信息成为必…

Chrome与夸克的安全性对比

在当今数字化时代&#xff0c;浏览器的安全性对于用户来说至关重要。Chrome和夸克作为两款流行的浏览器&#xff0c;各有其特点和优势。本文将对这两款浏览器的安全性进行详细对比&#xff0c;帮助用户更好地了解它们之间的差异。&#xff08;本文由https://www.chromegw.com/的…

穿越数据迷宫

第一章 在未来的世界里&#xff0c;人类的生活已经被高度数字化。互联网不再是简单的信息交换平台&#xff0c;而是成为了一个庞大的虚拟世界——“数据迷宫”。在这个世界里&#xff0c;每个人都有一个独特的数字身份&#xff0c;他们的生活、工作、娱乐都离不开这个虚拟空间…

日程安排工具Cal.com的安装

什么是 Cal.com (原 Calendso) ? Cal.com 是一个现代化、灵活且功能强大的开源日程管理平台&#xff0c;旨在为用户提供全面的控制权和定制能力&#xff0c;是适合每个人的活动日程安排程序&#xff0c;被誉为 Calendly 的继任者。它的最大特点是完全开源&#xff0c;用户可以…

论文阅读:Computational Long Exposure Mobile Photography (二)

这篇文章是谷歌发表在 2023 ACM transaction on Graphic 上的一篇文章&#xff0c;介绍如何在手机摄影中实现长曝光的一些拍摄效果。 Abstract 长曝光摄影能拍出令人惊叹的影像&#xff0c;用运动模糊来呈现场景中的移动元素。它通常有两种模式&#xff0c;分别产生前景模糊或…

Swift雨燕蜂窝无线通信系统介绍

本文博客链接:jdh99-CSDN博客,作者:jdh,转载请注明. 1. 概述 物联网小无线通信技术众多&#xff0c;其中大多是小范围小规模的无线通信技术&#xff0c;而行业难点是如何做到广覆盖、大容量、低功耗。 针对以上难点&#xff0c;宏讯物联研发了Swift雨燕蜂窝无线通信技术&…