Android 添加自己的时钟小部件

news2024/11/29 8:58:47

小部件,也叫微件,
它的介绍参考官网 应用 widget 概览 https://developer.android.google.cn/develop/ui/views/appwidgets/overview?hl=zh-cn

直接上图,原生系统上,时钟应用的小部件效果。
在这里插入图片描述

我也整一个。

1.创建小部件布局文件

这个文件就是最终显示在桌面的小部件的样式。
res/layout/time_widget_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="6dp"
    android:paddingBottom="6dp"
    android:gravity="center"
    android:orientation="vertical">

    <TextClock
        android:id="@+id/tv_date"
        android:layout_width="match_parent"
        android:layout_height="22dp"
        android:format12Hour="yyyy/MM/dd E"
        android:format24Hour="yyyy/MM/dd E"
        android:gravity="center"
        android:textSize="17sp"
        android:textColor="#DBE1FF" />

    <TextClock
        android:id="@+id/tv_time"
        android:layout_width="match_parent"
        android:layout_height="101dp"
        android:format12Hour="h:mm"
        android:format24Hour="HH:mm"
        android:gravity="center"
        android:textColor="#DBE1FF"
        android:textSize="@dimen/textclock_time_size" />

</LinearLayout>

使用 TextClock 显示日期、时间,很方便,它会自己更新,不需要添加刷新逻辑。

2.创建小部件配置文件

AppWidgetProviderInfo 对象定义了 widget 的基本特性。

resxml/time_widget.xml

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/time_widget_layout"
    android:minHeight="110dp"
    android:minWidth="110dp"
    android:resizeMode="vertical|horizontal"
    android:previewImage="@drawable/pic_beauty"
    android:updatePeriodMillis="3000" />
  • android:initialLayout :指向小部件布局文件 。
  • android:minHeight 、android:minWidth :小部件原始占用区域大小,也是最小占用区域大小,我的示例占用的是 2 x 2 。
  • android:resizeMode=“vertical|horizontal” :是否支持调整大小,这个是横向、纵向都支持。
  • android:previewImage :小部件的预览图。
  • android:updatePeriodMillis :小部件更新时间间隔。

小部件的大小要根据实际情况计算,参考官网示例
在这里插入图片描述
参考 Android Developers 应用微件设计指南

3.实现AppWidgetProvider

3.1 在清单中声明自定义的 AppWidgetProvider

AppWidgetProvider 本质是 receiver 。

        <receiver
            android:name=".appwidget.TimeWidgetProvider"
            android:exported="true"
            android:label="TimeWidgetLabel">
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/time_widget" />

            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
        </receiver>
  • android:name=“.appwidget.TimeWidgetProvider” :要实现的自定义 AppWidgetProvider
  • <meta-data/> 里的 android:name 是默认格式,不要改;android:resource 指向小部件配置文件。
  • <intent-filter> 里的是默认格式,不要修改。

3.2 实现自定义的 AppWidgetProvider

创建 TimeWidgetProvider ,继承 AppWidgetProvider

public class TimeWidgetProvider extends AppWidgetProvider {

    public static final String TAG = TimeWidgetProvider.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        Log.d(TAG, "onReceive : " + intent.getAction());
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        Log.d(TAG, "onUpdate");
    }
}

onReceive 里会接收到这些广播:

  • android.appwidget.action.APPWIDGET_ENABLED :小部件第一次被添加到桌面时触发。如果添加同一个小部件两次,第二次添加不会触发。对应 onEnabled 方法。
  • android.appwidget.action.APPWIDGET_UPDATE :小部件被添加到桌面或者小部件更新时触发。对应 onUpdate 方法。
  • android.appwidget.action.APPWIDGET_DELETED :小部件被删除时触发。如果同一个小部件有多个,删一个触发一次。对应 onDeleted方法。
  • android.appwidget.action.APPWIDGET_DISABLED :同一个小部件,最后一个被删除时触发。对应 onDisabled方法。
  • android.appwidget.action.APPWIDGET_UPDATE_OPTIONS :用户调整小部件大小时触发。对应 onAppWidgetOptionsChanged 方法。

到这里,初版已OK。

3.3 更新小部件

使用 RemoteViews 更新调整UI 、添加点击事件,然后调用 AppWidgetManager.updateAppWidget 即可。

	private RemoteViews remoteViews;
	private AppWidgetManager mAppWidgetManager;
    private int[] mAppWidgetIds;

	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        Log.d(TAG, "onUpdate");
        mAppWidgetManager = appWidgetManager;
        mAppWidgetIds = appWidgetIds;
        Log.d(TAG, "onUpdate appWidgetIds:" + Arrays.toString(mAppWidgetIds));
        createRemoteViews(context);
    }

    private void createRemoteViews(Context context) {
        if (remoteViews == null) {
            Log.d(TAG, "createRemoteViews");
            remoteViews = new RemoteViews(context.getPackageName(), R.layout.time_widget_layout);//注释1

            Intent intent = new Intent("android.settings.DATE_SETTINGS");
            intent.setPackage("com.android.settings");
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            
            PendingIntent pendingIntent1, pendingIntent2;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
                pendingIntent1 = PendingIntent.getActivity(context, 101, intent, PendingIntent.FLAG_IMMUTABLE);
                pendingIntent2 = PendingIntent.getActivity(context, 102, intent, PendingIntent.FLAG_IMMUTABLE);
            } else {
                pendingIntent1 = PendingIntent.getActivity(context, 101, intent, PendingIntent.FLAG_UPDATE_CURRENT);
                pendingIntent2 = PendingIntent.getActivity(context, 102, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
            remoteViews.setOnClickPendingIntent(R.id.tv_time, pendingIntent1);
            remoteViews.setOnClickPendingIntent(R.id.tv_date, pendingIntent2);//注释2

            for (int id:mAppWidgetIds) {
                mAppWidgetManager.updateAppWidget(id, remoteViews);//注释3
            }

        }

注释1 :通过 RemoteViews 找到 小部件布局文件,

RemoteViews 提供了很多方法更新小部件,如

  • setTextViewText(@IdRes int viewId, CharSequence text) :根据 id 设置 TextView 。
  • setImageViewResource(@IdRes int viewId, @DrawableRes int srcId) :根据 id 设置 ImageView。
  • setOnClickPendingIntent(@IdRes int viewId, PendingIntent pendingIntent) :根据 id 设置点击事件。

本例用的 TextClock ,会自动更新时间,就没有加 RemoteViews 的逻辑。

注释2 :使用 PendingIntent 为各个控件添加点击事件。如果不加,默认打开应用首页。本例打开原生设置的 日期和时间 。

注释3 :调用 AppWidgetManager.updateAppWidget 更新小部件。

最终效果:
在这里插入图片描述

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

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

相关文章

C#使用轻量级深度学习模型进行车牌颜色识别和车牌号识别

看到这个文章时候请注意这个不涉及到车牌检测&#xff0c;这个仅仅是车牌颜色和车牌号识别&#xff0c;如果想涉及到车牌检测可以参考这个博客&#xff1a;[C#]winform部署yolov7CRNN实现车牌颜色识别车牌号检测识别_c# yolo 车牌识别-CSDN博客 【训练源码】 https://github.…

已解决java.rmi.activation.ActivationException异常的正确解决方法,亲测有效!!!

已解决java.rmi.activation.ActivationException异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 问题分析 java.rmi.activation.ActivationException 是与Java RMI&#xff08;远程方法调用&#xff09;的激活机制相关的一种已检查异常。这个异…

【面试干货】Hashtable 与 HashMap 的区别

【面试干货】Hashtable 与 HashMap 的区别 1、线程安全性2、对null值的处理3、遍历方式4、遍历示例5、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;Hashtable和HashMap都是基于哈希表实现的Map接口。然而&#…

代码随想录算法训练营第31天| 134. 加油站、135. 分发糖果、860.柠檬水找零、 406.根据身高重建队列

134. 加油站 题目链接&#xff1a;134. 加油站 文档讲解&#xff1a;代码随想录 状态&#xff1a;so easy 思路&#xff1a;每次遍历时&#xff0c;如果当前的油量差&#xff08;currTank&#xff09;小于0&#xff0c;说明从当前起点无法到达下一个加油站。此时&#xff0c;将…

Python --- 如何修改Jupyter Notebook保存文件的路径?

如何修改Jupyter Notebook在本地保存文件的默认路径&#xff1f; 一直以来都比较喜欢jupter notebook&#xff0c;自从用了以后就爱上了。平时用的时候&#xff0c;因为大多都是临时调用&#xff0c;每次在界面里直接new一个新的file就开干。 曾经也想过我创建的这些python文件…

代码随想录第31天|贪心算法

134. 加油站 参考 思路: 以每个油站相差作为判断, 比如: gas [5 8 2 8]cost [6 5 6 6] [-1 3 -4 2]错误 : 把相差最大点当作起点判断能否绕一圈 : 相加数组是否小于0局部最优: 当前累加rest[i]的和curSum一旦小于0&#xff0c;起始位置至少要是i1&#xff0c;因为从i…

初识 SpringMVC,运行配置第一个Spring MVC 程序

1. 初识 SpringMVC&#xff0c;运行配置第一个Spring MVC 程序 文章目录 1. 初识 SpringMVC&#xff0c;运行配置第一个Spring MVC 程序1.1 什么是 MVC 2. Spring MVC 概述2.1 Spring MVC 的作用&#xff1a; 3. 运行配置第一个 Spring MVC 程序3.1 第一步&#xff1a;创建Mave…

免费开源的地图解析工具【快速上手】

视频学习地址 这篇文章和【Nominatim】是相呼应的&#xff0c;在尝试了OSM数据一直有问题之后&#xff0c;通过别人的指点是不是可以换个思路&#xff0c;我的数据只需要精确到市级别&#xff0c;也可以不用OSM这样全的数据&#xff08;主要原因还是OSM太过庞大了&#xff09; …

Mybatis(根据id查找这一行的数据)

首先在查询之前&#xff0c;我们先要做些基础的工作先创建一个以你的数据库命名的model类 我的数据库的名字叫admin 我就创建了一个Admin的类 用来方便数据的访问 然后我们就要创建一个接口来声明我们要写的方法 我创建的接口命名为AdminDao 在创建一个xml的类用来实现声明的…

NSSCTF中的[WUSTCTF 2020]朴实无华、[FSCTF 2023]源码!启动! 、[LitCTF 2023]Flag点击就送! 以及相关知识点

目录 [WUSTCTF 2020]朴实无华 [FSCTF 2023]源码&#xff01;启动! [LitCTF 2023]Flag点击就送&#xff01; 相关知识点 1.intval 绕过 绕过的方式&#xff1a; 2.session伪造攻击 [WUSTCTF 2020]朴实无华 1.进入页面几乎没什么可用的信息&#xff0c;所以想到使用dis…

408数据结构-图的应用1-最小生成树 自学知识点整理

前置知识&#xff1a;图的遍历 图的应用是408初试历年考查的重点。不过一般而言&#xff0c;这部分内容直接以算法设计题形式考查的可能性极小&#xff0c;更多的是结合图的实例来考查算法的具体操作过程&#xff0c;要求掌握的是手推模拟给定图的各个算法执行过程。此外&#…

利口 202. 快乐数

力扣 202. 快乐数 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结…

信号基本分析方法——频域分析

二、频域分析 随机信号的时域分析只能提供有限的时域故障特征信息&#xff0c;故障发生时往往会引起信号频率结构的变化&#xff0c;而故障频率可以计算和预知&#xff0c;通过检测频率的幅值变换规律&#xff0c;就可以监控故障的发展过程。 频谱分析的理论基础是傅里叶变换…

AI音乐模型:创新还是颠覆?

文章目录 AI音乐大模型的崛起音乐创作门槛的降低与兴奋AI音乐作品的版权归属问题创意产业在AI阴影下的生长结语 &#x1f389;欢迎来到AIGC人工智能专栏~探索Java中的静态变量与实例变量 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&…

【数据结构】链表的大概认识及单链表的实现

目录 一、链表的概念及结构 二、链表的分类 三、单链表的实现 建立链表的节点&#xff1a; 尾插——尾删&#xff1a; 头插——头删&#xff1a; 查找&#xff1a; 指定位置之后删除——插入&#xff1a; 指定位置之前插入——删除指定位置&#xff1a; 销毁链表&am…

向量和矩阵的点乘、叉乘

# 本科学习的全都还回去了-_- 一、向量 &#xff08;1&#xff09;点乘 向量点积&#xff0c; &#x1d44e;⋅&#x1d44f;&#x1d450; &#xff0c;符号为 ⋅ &#xff0c;要求向量长度相同&#xff0c;是两个向量之间的点乘运算&#xff0c;结果是一个标量。又称&…

在 Equinix 上使用 MinIO 控制云数据成本

公有云改变了公司构建、部署和管理应用程序的方式&#xff0c;主要是向好的方向发展。在您刚开始使用时&#xff0c;公有云会提供基础架构、服务、支持和维护&#xff0c;以便快速启动和运行。它以几乎无限的方式提供最终的可伸缩性&#xff0c;无论应用程序的负载如何&#xf…

ROS中的TF是什么

在ROS (Robot Operating System) 中&#xff0c;tf::TransformBroadcaster 是一个用于发布坐标变换信息的重要类&#xff0c;尤其在处理机器人定位和导航数据时非常常见。tf::TransformBroadcaster 对象允许你广播从一个坐标系到另一个坐标系的变换关系&#xff0c;这对于多传感…

c语言 课设 atm

功能需求分析 ATM功能主界面:显示所能进行的操作,用户可多次选择。 ATM注册界面:输入用户名,用户密码,确认密码,密码长度不是六位重新输入,两次密码不一致重新输入,输入账号。密码隐藏,实现退格换行对*无影响。多人注册 ATM登录界面:输入账号,密码,三次以内输入…

bug记录——C语言中运算符前假后面不执行

A&&B A为真&#xff0c;才会判断B&#xff0c; 所以如果B访问越界的情况下必有A为假&#xff0c;那么代码是正确的 像这里&#xff0c;当child 1 > n时&#xff0c;a[child 1]越界访问&#xff0c; 但由于&&前面判断了child 1 < n为假&#xff0c;所以…