android 自定义时钟控件

2023-11-08

效果截图:

 

自定义时钟组件源代码:

package com.sky_dreaming.analogic_clock.view;

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.res.Resources;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews.RemoteView;

import java.io.InputStream;
import java.util.TimeZone;

import com.sky_dreaming.analogic_clock.R;

@RemoteView
public class AnalogClock extends View {
	//时间
    private Time mCalendar;
    //时钟图片
    private Bitmap mDial;
    //设置图片
    private BitmapDrawable mDialDrawable;
    //时
    private BitmapDrawable mHourHandDrawable;
    //分
    private BitmapDrawable mMinuteHandDrawable;
    //秒
    private BitmapDrawable mSecondHandDrawable;
    //时钟宽度
    private int mDialWidth;
    //时钟高度
    private int mDialHeight;
    //是否点击
    private boolean mAttached = false;
    //现在时间--时
    private float mHours;
    //现在时间---分
    private float mMinutes;
    //现在时间--秒
    private float mSeconds;
    //现在时间字符串
    private String time_zone;
    
    public String getTime_zone() {
		return time_zone;
	}

	public void setTime_zone(String timeZone) {
		time_zone = timeZone;
	}
	
	/**
     *时间是否更改
     */
    private boolean mChanged;
    
    /**
     *主线程
     */
    private Handler loopHandler = new Handler();
    
    /**
     *是否运行
     */
    private boolean isRun = false;
    
    /**
     * 主线程处理(时间)
     */
    private void run()
    {
    	/**
    	 *时间更改线程
    	 */
    	loopHandler.post(tickRunnable);
    }
    private Runnable tickRunnable = new Runnable() {   
        public void run() {
        	/**
        	 * 方法待定
        	 */
        	postInvalidate();
        	/**
        	 * 10秒之后放入主线程之中
        	 */
            loopHandler.postDelayed(tickRunnable, 1000);   
        }   
    };   
	/**
	 * 相关构造方法
	 */
    public AnalogClock(Context context) {
        this(context, null);
    }

    public AnalogClock(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AnalogClock(Context context, AttributeSet attrs,
                       int defStyle) {
        super(context, attrs, defStyle);
        
        /**
         * 现在时间实例化
         */
        mCalendar = new Time();
        time_zone = mCalendar.timezone;
        
        Resources r = this.getContext().getResources();
		InputStream is =null;
		
		/**
		 * 资源图片读取
		 */
		is = r.openRawResource(R.drawable.clock);
		mDialDrawable = new BitmapDrawable(is);
		mDial = mDialDrawable.getBitmap();
		
		is = r.openRawResource(R.drawable.hands);
		mHourHandDrawable = new BitmapDrawable(is);
		
		is = r.openRawResource(R.drawable.hands);
		mMinuteHandDrawable = new BitmapDrawable(is);
		
		is = r.openRawResource(R.drawable.hands);
		mSecondHandDrawable = new BitmapDrawable(is);
		
        /**
         * 图片大小获取
         */
        mDialWidth = mDialDrawable.getIntrinsicWidth();
        mDialHeight = mDialDrawable.getIntrinsicHeight();
    }
    //view 相关覆写方法
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        if (!mAttached) {
            mAttached = true;
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_TIME_CHANGED);
            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
            getContext().registerReceiver(mIntentReceiver, filter, null, loopHandler);
        }

    }
    //view 相关覆写方法
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mAttached) {
            getContext().unregisterReceiver(mIntentReceiver);
            mAttached = false;
        }
    }
    //view 相关覆写方法
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize =  MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize =  MeasureSpec.getSize(heightMeasureSpec);

        float hScale = 1.0f;
        float vScale = 1.0f;

        if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
            hScale = (float) widthSize / (float) mDialWidth;
        }

        if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
            vScale = (float )heightSize / (float) mDialHeight;
        }

        float scale = Math.min(hScale, vScale);

        setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec),
                resolveSize((int) (mDialHeight * scale), heightMeasureSpec));
    }
    //view 相关覆写方法
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mChanged = true;
    }
    //view 相关覆写方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(!isRun)
        {
        	run();
        	isRun = true;
        	return;
        }
        //时间更改函数
        onTimeChanged();
        boolean changed = mChanged;
        if (changed) {
            mChanged = false;
        }

        int availableWidth = mDial.getWidth();
        int availableHeight = mDial.getHeight();

        int x = availableWidth / 2;
        int y = availableHeight / 2; 

        final Drawable dial = mDialDrawable;
        int w = dial.getIntrinsicWidth();
        int h = dial.getIntrinsicHeight();
        
        boolean scaled = false;

        if (availableWidth < w || availableHeight < h) {
            scaled = true;
            float scale = Math.min((float) availableWidth / (float) w,
                                   (float) availableHeight / (float) h);
            canvas.save();

            canvas.scale(scale, scale, x, y);
        }

        if (changed) {

            dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
        }
        dial.draw(canvas);

        canvas.save();

        canvas.rotate(mHours / 12.0f * 360.0f, x, y);
        final Drawable hourHand = mHourHandDrawable;
        if (changed) {
            w = hourHand.getIntrinsicWidth();
            h = hourHand.getIntrinsicHeight();
            hourHand.setBounds(x - (w / 2), y - (h * 2 / 3), x + (w / 2), y + (h / 3));
        }
        hourHand.draw(canvas);

        canvas.restore();

        canvas.save();
        canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);

        final Drawable minuteHand = mMinuteHandDrawable;
        if (changed) {
            w = minuteHand.getIntrinsicWidth();
            h = minuteHand.getIntrinsicHeight();
            minuteHand.setBounds(x - (w / 2), y - (h  * 4 / 5), x + (w / 2), y + (h / 5));
        }
        minuteHand.draw(canvas);
        canvas.restore();

        canvas.save();
        canvas.rotate(mSeconds / 60.0f * 360.0f, x, y);

        final Drawable scendHand = mSecondHandDrawable;
        if (changed) {
            w = scendHand.getIntrinsicWidth();
            h = scendHand.getIntrinsicHeight();
            scendHand.setBounds(x - (w / 2), y - h, x + (w / 2), y);
        }
        scendHand.draw(canvas);
        canvas.restore();

        if (scaled) {
            canvas.restore();
        }
    }
//自定义时间更改函数
    private void onTimeChanged() {

        mCalendar.setToNow();

        int hour = mCalendar.hour;
        int minute = mCalendar.minute;
        int second = mCalendar.second;
        
        mSeconds = second;
        mMinutes = minute + second / 60.0f;
        mHours = hour + mMinutes / 60.0f;
        
        mChanged = true;
    }
    //自定义广播
    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
        	String tz = "";
            if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
                tz = intent.getStringExtra("time-zone");
                mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
                time_zone = mCalendar.timezone;
            }
            Log.i("********************",tz);
            onTimeChanged();
            invalidate();
        }
    };
}


自定义时钟控件下载地址:http://download.csdn.net/detail/zhouzhiwengang/6366727

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android 自定义时钟控件 的相关文章

  • java 实现TCP和UDP的底层

    JAVA Socket 底层是怎样基于TCP IP 实现的 图片 2012 08 09 22 54 35 标签 java socket连接分类 JavaSE 首先必须明确 TCP IP模型中有四层结构 应用层 Application Lay
  • 在CentOS8中安装PHP8.0

    我的系统版本 cat etc redhat release 1 下载PHP安装文件 网址 https downloads php net pollita wget https downloads php net pollita php 8
  • 论文笔记:Temporal Regularized Matrix Factorization forHigh-dimensional Time Series Prediction

    0 摘要 时间序列预测问题在现代应用中变得越来越高维 如气候学和需求预测 例如 在需求预测中 项目数量可能高达50 000个 此外 数据通常是嘈杂的 充满缺失值 因此 现代应用程序需要高度可伸缩的方法 并且能够处理损坏或丢失值的噪声数据 然
  • 小程序下拉加载更多数据

    1 功能介绍 1 1 简单列表分页 功能描述 拖动下拉条 可以加载更多内容 1 1 1 实现步骤 1 1 1 1 配置 json文件 1 在app json页面配置 enablePullDownRefresh true 这会让下拉刷新效果适
  • STL 中查找算法使用总结

    顺序查找元素 find 头文件 包含在头文件 include 中 算法作用 使用 操作符 从给定的区间中查找和指定元素值相等的第一个元素 返回其迭代器 适用容器 适用于所有的序列容器 代码示例 vector
  • java 使用RabbitMQ示例

    RabbitMQ简介 RabbitMQ是一个受欢迎的消息代理 通常用于应用程序之间或者程序的不同组件之间通过消息来进行集成 具有高可用高并发的优点 适合集群服务器 采用 Erlang实现 对主要的编程语言都有客户端支持 RabbitMQ环境
  • java的JVM与垃圾回收机制

    核心机制 Java虚拟机 JVM是一个虚拟的计算机 具有指令集并使用不同的存储区域 负责执行指 令 管理数据 内存 寄存器 对于不同的平台 有不同的虚拟机 只有某平台提供了对应的java虚拟机 java程序才可在此平台运行 Java虚拟机机
  • python web自动化实现登录多次 利用ddt数据驱动读取账号信息

    web自动化实现多个用户登录某系统 使用python代码实现 首先创建读取测试数据的方法 代码如下 import unittest from time import sleep from ddt import ddt data 引入ddt驱
  • 【笔记】对称密码之分组密码的工作模式

    目录 一 前言 二 分组密码概述 2 1分组密码的设计原则 2 2混淆和扩散 三 分组加密法的模式 3 1电码本ECB Electronic Code Book 模式 3 2密码分组链接CBC Cipher Block Chaining 模
  • HTTP3

    当我对HTTP的认知还停留在HTTP2 0时 HTTP协议已经发展3 0了 参考下知乎 HTTP 3 原理实战 知乎 大厂对于新技术的追求总是处于行业前列 HTTP3就是其中之一 既然大厂都逐渐在使用了 那说明它经过了一系列的实践的考验 具
  • 二分搜索——分治思想

    二分查找 二分查找是一种在每次比较之后将查找空间一分为二的算法 每次需要查找集合中的索引或元素时 都应该考虑二分查找 如果集合是无序的 我们可以总是在应用二分查找之前先对其进行排序 时间复杂度是 log N 因为 二分查找是通过将现有数组一
  • 数据结构C语言 单链表(插入、删除、查找)

    数据结构C语言 单链表 插入 删除 查找 1 插入 假设 A 的临时指针为 p C 的临时指针为 q 步骤1 删除这条连接线 步骤2 将p gt next给q gt next 步骤3 将q给p gt next 插入代码 q gt next
  • ubuntu18.04+cuda10.2+cudnn7.6.5,并使用CUDA自动安装NVIDIA驱动而非手动。

    一 CUDA和NVIDIA显卡驱动安装 cuda的安装选项中其实包含了nvidia驱动的安装选项 不过网上好多资料都说不要再cuda中勾选nvidia驱动 而要自己去nvidia官网自己查好型号下载安装文件 手动安装nvidia驱动 其实主
  • 字体格式:ttf,woff,eot

    生成网页字体 https onlinefontconverter com eot IE onetype是微软和Adobe共同开发的字体 IE浏览器全部采用这种字体 woff 其它浏览器 woff web开发字体格式 是一种专门为web而设计

随机推荐

  • 信号延迟仿真的 Matlab 源码实现

    信号延迟仿真的 Matlab 源码实现 信号的延迟是数字信号处理中的一个重要概念 本文将介绍如何使用 Matlab 实现信号的延迟仿真 并给出相应的源代码实现 首先 我们需要定义一个信号并进行时域分析 在 Matlab 中 我们可以使用 t
  • Ubuntu下卸载Qt

    卸载有2种办法 1 进入qt的安装目录下卸载 一般ubuntu软件是安装在opt目录下 如果不在就需要找找了 进入安装目录下 sudo MaintenanceTool 选择remove all 就可以完全删除qt了 2 命令行安装的卸载 s
  • OVS datapath流表结构及匹配过程

    datapath流表的查找函数是ovs flow tbl lookup stats 在此之前 先看下datapath组织流表的方式 最新2 6的ovs流表 已经不是最早单纯的精确匹配了 而是一种精确匹配 带掩码匹配合并在一起的方式 叫做me
  • halcon像素统计_Halcon(八)亚像素轮廓XLD

    fast threshold Image Region 0 120 7 boundary Region RegionBorder inner dilation circle RegionClipped RegionDilation 2 5
  • Cox-Box变换

    在 回归分析的基本假设 中提到了回归分析中的基本假设 这里的Box Cox变换方法能够解决回归模型中的误差项不服从高斯分布的违例问题 通常这种违例情况出现在 误差 epsilon与预测变量相关的时候 会影响模型结果的精确度 简单的方法就是通
  • 了解redis的单线程模型工作原理?一篇文章就够了

    1 首先redis是单线程的 为什么redis会是单线程的呢 从redis的性能上进行考虑 单线程避免了上下文频繁切换问题 效率高 从redis的内部结构设计原理进行考虑 redis是基于Reactor模式开发了自己的网络事件处理器 这个处
  • 输入一个十进制数,输出其二进制,八进制,十六进制

    a int input 请输入一个十进制整数 print 其对应二进制为 b n八进制为 o n十六进制为 x format a a a
  • Java并发编程面试题——JUC专题

    一 AQS高频问题 1 1 AQS是什么 AQS是JUC下大量工具的基础类 很多工具都基于AQS实现的 比如lock锁 CountDownLatch Semaphore 线程池等等都用到了AQS AQS中有一个核心属性state 还有一个双
  • 基于react+and Design实现下拉框,支持自由输入

    基于react and Design实现下拉框 支持自由输入 以下是基于select的改造方案 使用AutoComplete组件更简单方便一些 AutoComplete这组件的实现方式请移步 基于react and Design实现下拉框
  • mysql 数据库授权(给某个用户授权某个数据库)

    mysql 数据库授权 给某个用户授权某个数据库 版权 1 小唐唐 https blog csdn net qq 38390092 article details 90340804 2 季枫 https www cnblogs com ji
  • PCB设计中常用的尺寸标注

    PCB设计中常用的尺寸标注 原创 凡亿教育 凡亿PCB 凡亿PCB 为了使设计者或生产者更方便地知晓PCB尺寸及相关信息 在设计的时候通常考虑到给设计好的PCB添加尺寸标注 尺寸标注方式分为线性 圆弧半径 角度等形式 下面对最常用的线性标注
  • canteen php,PHP脚本任务优化思路或改进方案?

    脚本部分 date default timezone set PRC require once canteen MySQL php mysql MySQL getInstance localhost root 123456 canteens
  • Oracle 修改字段非空属性问题

    背景 最近因为项目要做国际推广 然后在国外使用环境中有一个我们国内系统必填的字段是不需要的 导致一些问题所以需要修改数据库中对应字段的非空属性为允许为空 因为sql水平实在渣渣 只能网上搜索结果 找到一堆答案 但是没一个能成功执行的 不知是
  • ViewModelScope 避免内存泄漏的原理

    避免的是什么 避免的是协程的内存泄漏 如何避免 总体逻辑 通过 lifecycle 监听 Activity 的生命周期 在 Activity 销毁时对协程进行 cancel 监听状态变化 下图代码是注册监听的地方 可以看到在 Activit
  • 2014第五届蓝桥杯JavaB组决赛(国赛)试题汇总及试题详解

    蓝桥杯历年省赛真题汇总及题目详解 蓝桥杯历年决赛试题汇总及试题详解 目录 第一题 国王的遗产 第二题 六角幻方 第三题 格子放鸡蛋 第四题 排列序数 第五题 幂一矩阵 第六题 供水设施 第一题 国王的遗产 题目描述 X国是个小国 国王K有6
  • oracle数据库级别优化分析工具介绍

    author skatetime 2010 03 04 oracle数据库级别优化分析工具介绍 当我们对数据库优化诊断时 需要收集相应的信息以供参考 从个人的使用经验来说 这种统计数据分为两大类 一类是数据库级别的统计信息二类是os级别的统
  • 常见iPhone恢复固件(DFU模式)的三种方法

    可能你听说iPhone的DFU模式 DFU的全称是Development Firmware Upgrade 实际意思就是iPhone固件的强制升降级模式 例如 在你降级iPhone固件的时候 如果出现过错误 1 或者错误 6 那么在你恢复或
  • 如何使用ESP32相机模组实现视频流和人脸识别

    人证识别系统有许多种方式 比如使用签名 指纹 语音 面部识别等来识别人员 但是只有人脸识别系统可以检测和识别机场 零售店和火车站等公共场所中的人员 人脸识别系统不仅可以用于安全目的以识别公共场所中的人员 还可以用于办公室和学校中的考勤记录
  • ESP8266使用详解(AT,LUA,SDK)

    https www cnblogs com yangfengwu p 10100152 html 8266综合开发教程 AT LUA SDK 推荐 https www cnblogs com yangfengwu category 1187
  • android 自定义时钟控件

    效果截图 自定义时钟组件源代码 package com sky dreaming analogic clock view import android content Context import android content Inten