ToB企服应用市场:ToB评测及商务社交产业平台

标题: Android 桌面小组件使用 [打印本页]

作者: 商道如狼道    时间: 2024-10-10 07:22
标题: Android 桌面小组件使用
根本步调

1.创建小组件布局

这里须要留意的事,小组件布局里不能使用自定义View,只能使用原生的组件,比如说LinearLayout,TextView,连约束布局都不能使用
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="wrap_content"
  6.     android:background="@color/white"
  7.     android:orientation="vertical"
  8.     android:padding="16dp">
  9.     <LinearLayout
  10.         android:layout_width="match_parent"
  11.         android:layout_height="wrap_content"
  12.         android:orientation="horizontal">
  13.         <TextView
  14.             android:id="@+id/tvDate"
  15.             style="@style/textStyle14"
  16.             android:textColor="#313131"
  17.             android:layout_width="wrap_content"
  18.             android:layout_height="wrap_content"
  19.             android:text="2023-12-10" />
  20.         <ImageView
  21.             android:layout_width="0dp"
  22.             android:layout_height="wrap_content"
  23.             android:layout_weight="1" />
  24.         <TextView
  25.             android:id="@+id/tvTime"
  26.             android:textColor="#313131"
  27.             style="@style/textStyle14"
  28.             android:layout_width="wrap_content"
  29.             android:layout_height="wrap_content"
  30.             android:text="12:10" />
  31.     </LinearLayout>
  32.     <LinearLayout
  33.         android:layout_marginTop="16dp"
  34.         android:layout_width="match_parent"
  35.         android:layout_height="wrap_content"
  36.         android:orientation="horizontal">
  37.         <ImageView
  38.             android:layout_width="wrap_content"
  39.             android:layout_height="wrap_content"
  40.             android:src="@drawable/result_clean"/>
  41.         <LinearLayout
  42.             android:orientation="vertical"
  43.             android:layout_width="0dp"
  44.             android:layout_marginStart="9dp"
  45.             android:gravity="center_vertical"
  46.             android:layout_height="match_parent"
  47.             android:layout_weight="1" >
  48.             <TextView
  49.                 style="@style/textStyle14"
  50.                 android:textColor="#313131"
  51.                 android:textStyle="bold"
  52.                 android:layout_width="wrap_content"
  53.                 android:layout_height="wrap_content"
  54.                 android:text="125.4MB"/>
  55.             <TextView
  56.                 style="@style/textStyle14"
  57.                 android:textColor="#313131"
  58.                 android:textStyle="bold"
  59.                 android:layout_width="wrap_content"
  60.                 android:layout_height="wrap_content"
  61.                 android:text="Junk"/>
  62.         </LinearLayout>
  63.         <TextView
  64.             android:layout_gravity="center_vertical"
  65.             android:id="@+id/tvClean"
  66.             android:textColor="#313131"
  67.             style="@style/textStyle14"
  68.             android:layout_width="wrap_content"
  69.             android:layout_height="wrap_content"
  70.             android:text="Clean" />
  71.     </LinearLayout>
  72. </LinearLayout>
复制代码
2.创建provider

  1. import android.appwidget.AppWidgetManager
  2. import android.appwidget.AppWidgetProvider
  3. import android.content.Context
  4. import android.widget.RemoteViews
  5. import android.widget.RemoteViews.RemoteView
  6. import ten.jou.recover.R
  7. class CleaningWidget : AppWidgetProvider() {
  8.     override fun onUpdate(
  9.         context: Context,
  10.         appWidgetManager: AppWidgetManager,
  11.         appWidgetIds: IntArray
  12.     ) {
  13.         appWidgetIds.forEach {
  14.                         //如果小组件布局中使用不支持的组件,这里创建RemoteViews时候,IDE会报红提示!
  15.             val remoteView = RemoteViews(context.packageName, R.layout.widget_layout)
  16.                         //绑定数据
  17.                         remoteView.setTextViewText(R.id.tv1,"hello world")
  18.             appWidgetManager.updateAppWidget(it, remoteView)
  19.         }
  20.     }
  21. }
复制代码
AppWidgetProvider本质就是一个广播吸收器,以是在清单文件须要声明(见步调4)
这里先补充下,RemoteViews对于TextView,ImageView等View,有设置文本,字体颜色,图片等相关方法,但并不是全部方法都支持,绑定数据的时间须要留意下小组件是否支持!
3.创建xml属性声明

在xml文件夹里新建widget_info.xml文件:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:tools="http://schemas.android.com/tools"
  4.     android:targetCellWidth="4"
  5.     android:targetCellHeight="2"
  6.     android:minWidth="250dp"
  7.     android:minHeight="110dp"
  8.     android:updatePeriodMillis="0"
  9.     android:initialLayout="@layout/widget_layout"
  10.     tools:targetApi="s">
  11. </appwidget-provider>
复制代码
Android12版本以上新增的2个属性,声明组件是4*2大小

4.清单文件声明

  1. <receiver
  2.         android:name=".view.CleaningWidget"
  3.         android:enabled="true"
  4.         android:exported="true">
  5.         <intent-filter>
  6.                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
  7.         </intent-filter>
  8.         <meta-data
  9.                 android:name="android.appwidget.provider"
  10.                 android:resource="@xml/widget_info" />
  11. </receiver>
复制代码
5.代码添加小组件

官方说Android12不允许直接通过代码添加小组件,只能让用户手动去桌面拖动添加,但是我手头的三星体系却是支持的(也是Android12),具体还没有细究...
而官方文档上的写的例子如下:
  1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  2.         val context = this@DesktopWidgetActivity
  3.         val appWidgetManager: AppWidgetManager =
  4.                 context.getSystemService(AppWidgetManager::class.java)
  5.         val myProvider = ComponentName(context, CleaningWidget::class.java)
  6.         //判断启动器是否支持小组件pin
  7.         val successCallback = if (appWidgetManager.isRequestPinAppWidgetSupported) {
  8.                 // Create the PendingIntent object only if your app needs to be notified
  9.                 // that the user allowed the widget to be pinned. Note that, if the pinning
  10.                 // operation fails, your app isn't notified.
  11.                 Intent(context, CleaningWidget::class.java).let { intent ->
  12.                         // Configure the intent so that your app's broadcast receiver gets
  13.                         // the callback successfully. This callback receives the ID of the
  14.                         // newly-pinned widget (EXTRA_APPWIDGET_ID).
  15.                         //适配android12的
  16.                         val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
  17.                                 PendingIntent.FLAG_MUTABLE
  18.                         } else {
  19.                                 PendingIntent.FLAG_UPDATE_CURRENT
  20.                         }
  21.                         PendingIntent.getBroadcast(
  22.                                 context,
  23.                                 0,
  24.                                 intent,
  25.                                 flags
  26.                         )
  27.                 }
  28.         } else {
  29.                 null
  30.         }
  31.         appWidgetManager.requestPinAppWidget(myProvider, null, successCallback)
  32. }
复制代码
这里提下,上面的设置flags方法
  1. val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
  2.         PendingIntent.FLAG_MUTABLE
  3. } else {
  4.         PendingIntent.FLAG_UPDATE_CURRENT
  5. }
复制代码
有个新项目的targetSdk为34(即Android14),假如使用上面的代码会出现下面瓦解错误提示
  1. Targeting U+ (version 34 and above) disallows creating or retrieving a PendingIntent with FLAG_MUTABLE, an implicit Intent within and without FLAG_NO_CREATE and FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for security reasons. To retrieve an already existing PendingIntent, use FLAG_NO_CREATE, however, to create a new PendingIntent with an implicit Intent use FLAG_IMMUTABLE.
复制代码
实际上提示已经告诉我们怎么去改代码了,我这里把PendingIntent.FLAG_MUTABLE改为FLAG_IMMUTABLE就不会出现了上述的瓦解问题
应该是Android14添加的限制:

定时刷新小组件UI

首先,我们得知道,怎样主动去更新数据:
  1. val context = it.context
  2. val appWidgetManager: AppWidgetManager = context.getSystemService(AppWidgetManager::class.java)
  3. val myProvider = ComponentName(context, CleaningWidget::class.java)
  4. val remoview = CleaningWidget.getRemoteViewTest(context)
  5. //更新某类组件
  6. appWidgetManager.updateAppWidget(myProvider,remoview)
  7. //更新具体某个组件id
  8. appWidgetManager.updateAppWidget(widgetId,remoview)
复制代码
getRemoteViewTest方法就是创建一个remoteview,然后调用remoteview相关方法设置文本之类的举行数据填充,代码就略过不写了,详见上述根本步调2
上面的方法我们留意到updateAppWidget可以传差别的参数,一样寻常我们用的第二个方法,指定更新某个组件
但这里又是须要我们传一个组件id,以是就是在步调2的时间,我们根据须要须要存储下widgetId比力好,一样寻常存入数据库,或者使用SharePreference也可
然后,就是对于定时的情况和对应方案:
应该是除了第一种方法,其他都是可以在应用被杀死的情况举行更新小组件UI
小组件播放动画

progressbar实现

帧动画不手动调用anim.start()方法是不会播放的,然后在网上看到一篇文章,使用了progressbar来实现,步调如下:
在drawable文件夹准备帧动画文件
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" android:visible="true">
  3.     <item android:drawable="@drawable/cat_1" android:duration="100" />
  4.     <item android:drawable="@drawable/cat_2" android:duration="100" />
  5.     <item android:drawable="@drawable/cat_3" android:duration="100" />
  6.     <item android:drawable="@drawable/cat_4" android:duration="100" />
  7. </animation-list>
复制代码
  1. <ProgressBar
  2.         android:indeterminateDrawable="@drawable/cat_animdrawable"
  3.         android:layout_width="wrap_content"
  4.         android:layout_height="wrap_content"/>
复制代码
indeterminateDrawable设置为上面的帧动画文件即可
layoutanim实现

主要是利用viewgroup的初次显示的时间,会展示当前view的添加动画效果,从而实现比力简单的动画效果,如平移,缩放等
可以看实现的敲木鱼一文Android-桌面小组件RemoteViews播放木鱼动画 - 掘金
使用ViewFlipper

ViewFlipper主要是轮播使用的
里面可放几个元素,之后通过设置autoStart为true,则包管主动轮播
flipInterval属性则是每个元素的间隔时间(帧动画的时间),单位为ms
不过在remoteview中使用的话,缺点就是里面的元素数量只能固定死
否则只能通过定义差别layout文件(如3个元素则是某个layout,4个元素则是某个layout,然后根据选择来创建remoteview)
  1. <ViewFlipper
  2.         android:id="@+id/viewFlipper"
  3.         android:layout_width="match_parent"
  4.         android:layout_height="match_parent"
  5.         android:layout_gravity="center"
  6.         android:layout_margin="4dp"
  7.         android:autoStart="true"
  8.         android:flipInterval="800">
  9.         <ImageView
  10.             android:id="@+id/vf_img_1"
  11.             android:layout_width="match_parent"
  12.             android:layout_height="match_parent"
  13.             android:scaleType="fitXY"
  14.             android:src="@drawable/peace_talisman_1" />
  15.         <ImageView
  16.             android:id="@+id/vf_img_2"
  17.             android:layout_width="match_parent"
  18.             android:layout_height="match_parent"
  19.             android:scaleType="fitXY"
  20.             android:src="@drawable/peace_talisman_2" />
  21.     </ViewFlipper>
复制代码
补充

获取当前桌面的组件id列表

  1. //获得当前桌面已添加的组件的id列表(可能用户添加了多个)
  2. val context = it.context
  3. val appWidgetManager: AppWidgetManager = context.getSystemService(AppWidgetManager::class.java)
  4. val myProvider = ComponentName(context, CleaningWidget::class.java)
  5. val info =appWidgetManager.getAppWidgetIds(myProvider)
  6. toast(info.size.toString())
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4