赞
踩
这里需要注意的事,小组件布局里不能使用自定义View,只能使用原生的组件,比如说LinearLayout,TextView,连约束布局都不能使用
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@color/white"
- android:orientation="vertical"
- android:padding="16dp">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <TextView
- android:id="@+id/tvDate"
- style="@style/textStyle14"
- android:textColor="#313131"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="2023-12-10" />
-
- <ImageView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1" />
-
- <TextView
- android:id="@+id/tvTime"
- android:textColor="#313131"
- style="@style/textStyle14"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="12:10" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_marginTop="16dp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/result_clean"/>
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="0dp"
- android:layout_marginStart="9dp"
- android:gravity="center_vertical"
- android:layout_height="match_parent"
- android:layout_weight="1" >
- <TextView
- style="@style/textStyle14"
- android:textColor="#313131"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="125.4MB"/>
- <TextView
- style="@style/textStyle14"
- android:textColor="#313131"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Junk"/>
- </LinearLayout>
-
- <TextView
- android:layout_gravity="center_vertical"
- android:id="@+id/tvClean"
- android:textColor="#313131"
- style="@style/textStyle14"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Clean" />
-
- </LinearLayout>
-
- </LinearLayout>
- import android.appwidget.AppWidgetManager
- import android.appwidget.AppWidgetProvider
- import android.content.Context
- import android.widget.RemoteViews
- import android.widget.RemoteViews.RemoteView
- import ten.jou.recover.R
-
- class CleaningWidget : AppWidgetProvider() {
- override fun onUpdate(
- context: Context,
- appWidgetManager: AppWidgetManager,
- appWidgetIds: IntArray
- ) {
- appWidgetIds.forEach {
- //如果小组件布局中使用不支持的组件,这里创建RemoteViews时候,IDE会报红提示!
- val remoteView = RemoteViews(context.packageName, R.layout.widget_layout)
- //绑定数据
- remoteView.setTextViewText(R.id.tv1,"hello world")
- appWidgetManager.updateAppWidget(it, remoteView)
- }
-
- }
- }
AppWidgetProvider本质就是一个广播接收器,所以在清单文件需要声明(见步骤4)
这里先补充下,RemoteViews对于TextView,ImageView等View,有设置文本,字体颜色,图片等相关方法,但并不是所有方法都支持,绑定数据的时候需要注意下小组件是否支持!
在xml文件夹里新建widget_info.xml文件:
- <?xml version="1.0" encoding="utf-8"?>
- <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:targetCellWidth="4"
- android:targetCellHeight="2"
- android:minWidth="250dp"
- android:minHeight="110dp"
- android:updatePeriodMillis="0"
- android:initialLayout="@layout/widget_layout"
- tools:targetApi="s">
- </appwidget-provider>
Android12版本以上新增的2个属性,声明组件是4*2大小
- <receiver
- android:name=".view.CleaningWidget"
- android:enabled="true"
- android:exported="true">
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
- </intent-filter>
- <meta-data
- android:name="android.appwidget.provider"
- android:resource="@xml/widget_info" />
- </receiver>
官方说Android12不允许直接通过代码添加小组件,只能让用户手动去桌面拖动添加,但是我手头的三星系统却是支持的(也是Android12),具体还没有细究...
而官方文档上的写的例子如下:
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val context = this@DesktopWidgetActivity
-
- val appWidgetManager: AppWidgetManager =
- context.getSystemService(AppWidgetManager::class.java)
- val myProvider = ComponentName(context, CleaningWidget::class.java)
-
- //判断启动器是否支持小组件pin
- val successCallback = if (appWidgetManager.isRequestPinAppWidgetSupported) {
- // Create the PendingIntent object only if your app needs to be notified
- // that the user allowed the widget to be pinned. Note that, if the pinning
- // operation fails, your app isn't notified.
- Intent(context, CleaningWidget::class.java).let { intent ->
- // Configure the intent so that your app's broadcast receiver gets
- // the callback successfully. This callback receives the ID of the
- // newly-pinned widget (EXTRA_APPWIDGET_ID).
- //适配android12的
- val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- PendingIntent.FLAG_MUTABLE
- } else {
- PendingIntent.FLAG_UPDATE_CURRENT
- }
- PendingIntent.getBroadcast(
- context,
- 0,
- intent,
- flags
- )
- }
- } else {
- null
- }
-
- appWidgetManager.requestPinAppWidget(myProvider, null, successCallback)
- }
这里提下,上面的设置flags方法
- val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- PendingIntent.FLAG_MUTABLE
- } else {
- PendingIntent.FLAG_UPDATE_CURRENT
- }
有个新项目的targetSdk为34(即Android14),如果使用上面的代码会出现下面崩溃错误提示
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添加的限制:
PendingIntent.FLAG_IMMUTABLE
PendingIntent.FLAG_MUTABLE
首先,我们得知道,如何主动去更新数据:
- val context = it.context
- val appWidgetManager: AppWidgetManager = context.getSystemService(AppWidgetManager::class.java)
- val myProvider = ComponentName(context, CleaningWidget::class.java)
- val remoview = CleaningWidget.getRemoteViewTest(context)
-
- //更新某类组件
- appWidgetManager.updateAppWidget(myProvider,remoview)
- //更新具体某个组件id
- appWidgetManager.updateAppWidget(widgetId,remoview)
getRemoteViewTest方法就是创建一个remoteview,然后调用remoteview相关方法设置文本之类的进行数据填充,代码就略过不写了,详见上述基本步骤2
上面的方法我们注意到updateAppWidget
可以传不同的参数,一般我们用的第二个方法,指定更新某个组件
但这里又是需要我们传一个组件id,所以就是在步骤2的时候,我们根据需要需要存储下widgetId比较好,一般存入数据库,或者使用SharePreference也可
然后,就是对于定时的情况和对应方案:
应该是除了第一种方法,其他都是可以在应用被杀死的情况进行更新小组件UI
帧动画不手动调用anim.start()
方法是不会播放的,然后在网上看到一篇文章,使用了progressbar来实现,步骤如下:
在drawable文件夹准备帧动画文件
- <?xml version="1.0" encoding="utf-8"?>
- <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" android:visible="true">
- <item android:drawable="@drawable/cat_1" android:duration="100" />
- <item android:drawable="@drawable/cat_2" android:duration="100" />
- <item android:drawable="@drawable/cat_3" android:duration="100" />
- <item android:drawable="@drawable/cat_4" android:duration="100" />
- </animation-list>
- <ProgressBar
- android:indeterminateDrawable="@drawable/cat_animdrawable"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
indeterminateDrawable设置为上面的帧动画文件即可
主要是利用viewgroup的初次显示的时候,会展示当前view的添加动画效果,从而实现比较简单的动画效果,如平移,缩放等
可以看实现的敲木鱼一文Android-桌面小组件RemoteViews播放木鱼动画 - 掘金
ViewFlipper主要是轮播使用的
里面可放几个元素,之后通过设置autoStart为true,则保证自动轮播
flipInterval属性则是每个元素的间隔时间(帧动画的时间),单位为ms
不过在remoteview中使用的话,缺点就是里面的元素数目只能固定死
否则只能通过定义不同layout文件(如3个元素则是某个layout,4个元素则是某个layout,然后根据选择来创建remoteview)
- <ViewFlipper
- android:id="@+id/viewFlipper"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:layout_margin="4dp"
- android:autoStart="true"
- android:flipInterval="800">
-
- <ImageView
- android:id="@+id/vf_img_1"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="fitXY"
- android:src="@drawable/peace_talisman_1" />
-
- <ImageView
- android:id="@+id/vf_img_2"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="fitXY"
- android:src="@drawable/peace_talisman_2" />
- </ViewFlipper>
- //获得当前桌面已添加的组件的id列表(可能用户添加了多个)
- val context = it.context
- val appWidgetManager: AppWidgetManager = context.getSystemService(AppWidgetManager::class.java)
- val myProvider = ComponentName(context, CleaningWidget::class.java)
-
- val info =appWidgetManager.getAppWidgetIds(myProvider)
- toast(info.size.toString())
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。