เกี่ยวกับ Codelab นี้
1 准备工作
此 Codelab 会引导您完成为 SociaLite 创建应用 widget 的过程。首先,您将构建一个简单的 Glance widget,并将其添加到 SociaLite 和主屏幕中。接下来,您将使用 Glance 组件和 Glance 主题向 widget 添加零状态。然后,本 Codelab 将引导您支持用户互动,以便从 widget 中选择您喜爱的联系人。最后,您将了解如何从应用中更新 widget。
前提条件
- 具备 Kotlin 基础知识。
- 已完成设置 Android Studio Codelab,或者熟悉如何在 Android 15 模拟器或搭载 Android 15 的实体设备中使用 Android Studio 并测试应用
- 具备基本的 Hilt 知识。
- 具备 Compose 基础知识Glance 不使用 Jetpack Compose 中的可组合项,但会重复使用框架和编码样式。
您将在此 Codelab 中学到的内容
- 如何将应用配置为支持 widget。
- 如何使用 Glance 组件构建自适应布局。
- 如何使用
GlanceTheme
在用户的主屏幕上支持动态配色。 - 如何在 widget 中处理用户互动。
- 如何通过应用更新 widget。
所需条件
- 最新版本的 Android Studio。
- 搭载 Android 12 或更高版本的测试设备或模拟器。
- Android 12 或更高版本的 SDK。
2 进行设置
获取起始代码
- 如果您已完成“在 Android 15 中处理无边框强制执行”或“添加预测性返回动画”Codelab,请继续阅读添加 widget部分,因为您已有起始代码。
- 从 GitHub 下载起始代码。
或者,您也可以克隆代码库并查看 codelab_improve_android_experience_2024 分支。
git clone git@github.com:android/socialite.git
cd socialite
git checkout codelab_improve_android_experience_2024
- 在 Android Studio 中打开 SociaLite,然后在搭载 Android 15 的设备或模拟器上运行该应用。您将看到如下所示的界面:
采用手势导航的 SociaLite
3 添加微件
什么是 widget?
widget 是可以嵌入到其他 Android 应用中的应用组件。最常见的是用户的主屏幕。
向应用添加 widget 可让用户快速启动常见任务、查看一目了然的信息,并使用您的内容自定义设备。
什么是 Glance?
Jetpack Glance 是一个库,用于使用 Kotlin 中的 Compose 类 API 编写 widget。它具有与 Compose 相同的多项优势,例如重组、使用 Kotlin 编写的声明性界面代码以及自定义组件。Glance 消除了在 widget 中使用 XML 远程视图的大部分需求。
创建 widget
Android 上的 widget 在 AndroidManifest
中声明为 <receiver>
元素。此接收器应被导出,处理 android.appwidget.action.APPWIDGET_UPDATE
操作 intent,并通过名为 android.appwidget.provider
的元数据元素提供应用 widget 设置文件。
向 SociaLite 添加 widget
您想向 Socialite 添加一个 widget,让用户可以查看自己最喜欢的联系人以及是否有来自此人的未读消息。如果有,点按该 widget 应该会将用户引导至其最喜欢的联系人的聊天对话。此外,您还可以使用 Glance 组件和主题,通过采用自适应设计和动态配色来确保 widget 外观最佳。
首先,您需要向 Socialite 添加静态“Hello World”widget。然后,您可以扩展 widget 的功能。
为此,您需要执行以下操作:
- 将 Glance 依赖项添加到您的应用。
- 创建
GlanceAppWidget
的实现。 - 创建
GlanceAppWidgetReceiver
。 - 使用应用 widget 信息 XML 文件配置 widget。
- 将接收器和应用 widget 信息添加到
AndroidManifest.xml
文件中。
将 Glance 添加到您的项目中
起始代码已将 Glance 版本和库坐标添加到 SociaLite 的版本目录:libs.versions.toml
。
libs.versions.toml
[versions]
//..
glance = "1.1.0-beta02"
[libraries]
glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "glance" }
glance-material = { group = "androidx.glance", name = "glance-material3", version.ref = "glance" }
此外,Glance 的依赖项包含在 SociaLite 的 app/build.gradle.kts
文件中。
build.gradle.kts
dependencies {
...
implementation(libs.glance.appwidget)
implementation(libs.glance.material)
...
}
- 如果您修改了这些文件,请同步项目以下载 Glance 库。
创建 GlanceAppWidget
和 GlanceAppWidgetReceiver
Android 使用广播接收器来提醒 SociaLite,某个 widget 已添加、需要更新或已移除。Glance 提供了一个抽象接收器类 GlanceAppWidgetReceiver,它会扩展 AppWidgetProvider。
GlanceAppWidgetReceiver
实现还负责提供 GlanceAppWidget
的实例。此类会将 Glance 的可组合项渲染到远程视图中。
起始代码包含两个类:会扩展 GlanceAppWidget
的 SocialiteAppWidget
,以及会扩展 GlanceAppWidgetReceiver
的 SocialiteAppWidgetReceiver
。
若要开始,请按照以下步骤操作:
- 前往
app/src/main/java/com/google/android/samples/socialite/
中的widget
软件包。 - 打开
SociaLiteAppWidget
类。此类会替换provideGlance
方法。 - 将
TODO
替换为对provideContent
的调用,然后将 widget 的可组合函数作为参数传递。目前,该 widget 仅显示消息Hello World
,但您稍后会在此 Codelab 中添加更多功能。
package com.google.android.samples.socialite.widget
import android.content.Context
import androidx.glance.GlanceId
import androidx.glance.GlanceTheme
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.provideContent
import androidx.glance.text.Text
class SociaLiteAppWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
GlanceTheme {
Text("Hello World")
}
}
}
}
- 打开
widget
软件包中的SociaLiteAppWidgetReceiver
类。目前,您的接收器提供SociaLiteWidget
的实例,但您将在后面的部分中添加更多功能。 - 将
TODO
替换为SociaLiteAppWidget()
构造函数:
package com.google.android.samples.socialite.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class SociaLiteAppWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = SociaLiteAppWidget()
}
现在,您可配置 Android 以显示您的 widget,并允许用户将其添加到主屏幕。
添加应用 widget 提供程序信息
- 右键点击 res/xml > New > XML resource file。
- 输入 socialite_widget_info 作为文件名,输入 appwidget-provider 作为根元素,然后点击 OK。此文件包含
appwidget
的元数据,这些数据会被AppWidgetHost
用以初始显示该 widget。 - 将以下代码添加到 socialite_widget_info.xml 文件中:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000"
android:minHeight="128dp"
android:minWidth="128dp"
android:minResizeHeight="128dp"
android:minResizeWidth="128dp"
android:configure="com.google.android.samples.socialite.widget.SociaLiteAppWidgetConfigActivity"
android:widgetFeatures="configuration_optional|reconfigurable"
android:previewImage="@drawable/widget_preview"
android:maxResizeHeight="512dp"
android:maxResizeWidth="512dp"
android:targetCellWidth="2"
android:targetCellHeight="2"
android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>
下表简要介绍了此代码中的属性,并说明了每个属性:
属性名称 | 说明 |
| 您的 widget 可能会在垂直和水平方向上调整大小。 |
| 指定将 widget 添加到主屏幕时的默认大小。 |
| 用于控制 widget 主机何时决定刷新 widget。您的应用可以在运行时更新 widget,并显示新信息。 |
| 设定可将 widget 的尺寸调整到多小。 |
| 指定将 widget 添加到主屏幕时的默认最小尺寸。 |
| 在 Glance 呈现可组合项时提供显示的初始布局。 |
| 提供要在 widget 选择器中显示的 widget 的静态图片。 |
| 指明该 widget 支持的各种功能。这些提示是针对 widget 主机的,实际上不会更改 widget 的行为。 |
| 配置 activity 类的名称。此 activity 稍后会配置 widget。 |
如需查看所有可用属性(包括 API 31 或更高级别中的功能),请参阅 AppWidgetProviderInfo
。
更新 AndroidManifest
并测试
最后,您可以更新 AndroidManifest.xml
文件并测试 widget 了。您可以将 receiver
元素定义为文件中 application
元素的子元素。此接收器会处理 APPWIDGET_UPDATE
intent,并向 Android 启动器提供 appwidget
元数据。
若要开始,请按照以下步骤操作:
- 为要导出的
SociaLiteAppWidgetReceiver
创建receiver
元素。将以下代码复制并粘贴到AndroidManifest.xml
文件中的application
元素后面:
<receiver
android:name=".widget.SociaLiteAppWidgetReceiver"
android:exported="true"
android:label="Favorite Contact">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/socialite_widget_info" />
</receiver>
- 编译并运行您的应用。
- 应用运行后,将该 widget 添加到主屏幕。例如,在 Pixel 上,长按背景,然后依次选择 widget > SociaLite。您应该能够将该 widget 添加到主屏幕。
您的 widget 显示“Hello World”,并具有透明背景。诚然,这还不是外观最出众或功能最强大的 widget。在下一部分中,您将添加更复杂的布局,并使用 Material Design 颜色美化 widget。
4 改进设计
现在,您有了一个静态 widget,但它缺少优质 widget 需要具备的许多功能。优质 widget 会执行以下操作:
- 保持内容新鲜且简短,并保持功能简单。
- 通过可调整大小的布局最大限度地减少尴尬的间隙。
- 会采用应用 widget 托管背景中的颜色。
如需深入了解如何打造优质 widget,请参阅 widget。
添加 Scaffold
现在,您可更新自己的 widget,以便在 Glance Scaffold
组件中显示。
Scaffold
由 Glance 库提供。这是一个简单的槽 API,用于使用 TitleBar
显示 widget 界面。它会将背景颜色设为 GlanceTheme.colors.widgetBackground
并应用内边距。它将成为您的顶级组件。
若要开始,请按照以下步骤操作:
- 将
SociaLiteAppWidget
的实现替换为以下代码:
package com.google.android.samples.socialite.widget
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.ImageProvider
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.components.Scaffold
import androidx.glance.appwidget.components.TitleBar
import androidx.glance.appwidget.provideContent
import androidx.glance.layout.fillMaxSize
import androidx.glance.text.Text
import com.google.android.samples.socialite.R
class SociaLiteAppWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
GlanceTheme() {
Content()
}
}
}
@Composable
private fun Content() {
Scaffold(titleBar = {TitleBar(startIcon = ImageProvider(R.drawable.ic_launcher_monochrome), title = "SociaLite")},
modifier = GlanceModifier.fillMaxSize()) {
Text("Hello World")
}
}
}
- 如需查看更新,请重新运行应用,然后将 widget 的新副本添加到主屏幕。
请记住,widget 是由外部主机显示的远程视图。稍后,您将添加会自动在应用内更新 widget 的功能。在那之前,您必须从 widget 选择器中添加 widget 才能查看代码更改。
如您所见,这要好得多,但当您将自己的 widget 与其他 widget 进行比较时,颜色似乎不对。在主屏幕上,widget 应根据用户的主题设置来设置颜色。借助动态颜色令牌,您可以让 widget 的主题契合设备的壁纸和主题。
添加动态配色
现在,您可以将 widgetBackground
颜色令牌添加到 Scaffold 背景,将 onSurface
颜色令牌添加到 TitleBar
文本和文本组件。若要更新文本样式,您需导入 TextStyle
Glance 类。如需更新 Scaffold 背景,请将 Scaffold
的 backgroundColor
属性设为 GlanceTheme.colors.widgetBackground
。
若要开始,请按照以下步骤操作:
- 在 SociaLiteAppWidget.kt 文件中添加新导入项。
//Add to the imports section of your Kotlin code.
import androidx.glance.text.TextStyle
- 更新
Content
可组合项以添加widgetBackground
。
Scaffold(
titleBar = {
TitleBar(
textColor = GlanceTheme.colors.onSurface,
startIcon = ImageProvider(R.drawable.ic_launcher_monochrome),
title = "SociaLite",
)
},
backgroundColor = GlanceTheme.colors.widgetBackground,
modifier = GlanceModifier.fillMaxSize(),
) {
Text(text = "Hello World", style = TextStyle(color = GlanceTheme.colors.onSurface))
}
- 如需查看更新,请重新运行应用,然后将 widget 的新副本添加到主屏幕。
它会与主屏幕上其他 widget 的主题相匹配,并在您更改背景或设置深色模式时自动更新颜色。对于色彩丰富的背景,widget 会根据其所在的背景部分进行调整。
|
|
添加零状态
现在,您需要考虑状态并配置 widget。当将 widget 添加到主屏幕并需要进行配置时,通常最好显示零状态。零状态会提示用户配置 widget。您可以向 widget 添加配置 activity,并从零状态链接到该 activity。
此 Codelab 提供了用于存储、访问和修改 widget 配置状态的类。您将添加代码来更新 widget 的界面以显示此状态,并创建 lambda 操作来处理用户点按操作。
查看 widget 模型
请花点时间查看软件包 com.google.android.samples.socialite.widget.model
中的类。
这包括 WidgetModel
类以及 WidgetModelDao
和 WidgetModelRepository
类。这些类已存在于 Codelab 起始代码中,并负责将 widget 的状态持久存储到底层 Room
数据库。此外,这些类使用 Hilt 来管理各自的生命周期。
WidgetModel
类包含由 Android 分配的 widgetId
、所显示 SociaLite 联系人的 contactId
、要显示的 displayName
和 photo
,以及表明联系人是否有未读消息的布尔值。这些数据将由 SociaLiteAppWidget
可组合项使用,并显示在 widget 中。
WidgetModelDao
是一个数据访问对象,用于抽象化对 SociaLite 数据库的访问。WidgetModelRepository
提供了用于创建、读取、更新和删除 WidgetModel
实例的便捷函数。这些类由 Hilt 创建,并通过依赖项注入功能注入到应用中。
- 打开位于
app/src/main/java/com/google/android/samples/socialite/widget/model/
的model
软件包中的WidgetModel.kt
文件。
它是一个带有 Entity
注解的 data
类。Android 会为每个 widget 实例分配一个专用 ID,而 SociaLite 会将此 ID 用作模型数据的主键。该模型的每个实例都会跟踪所关联的联系人的基本信息,以及此人是否有未读消息。
@Entity(
foreignKeys = [
ForeignKey(
entity = Contact::class,
parentColumns = ["id"],
childColumns = ["contactId"],
onDelete = ForeignKey.CASCADE,
),
],
indices = [
Index("widgetId"),
Index("contactId"),
],
)
data class WidgetModel(
@PrimaryKey val widgetId: Int,
val contactId: Long,
val displayName: String,
val photo: String,
val unreadMessages: Boolean = false,
) : WidgetState
零状态
您希望 Content
可组合项从 WidgetModelRepository
加载 widget 的模型并在没有可用模型时显示零状态;否则,您希望显示 widget 的常规内容。目前,这将是您的“Hello World”消息,但在下一部分中,您将创建更好的界面。
您将 Content
可组合项替换为显示 ZeroState
可组合项或 Text
占位符的 when
表达式。
- 在
provideGlance
方法中,在可组合项之外,获取对WidgetModelRepository
和当前 widget ID 的引用。在SociaLiteAppWidget
provideGlance
方法中的provideContent
前面添加以下几行代码。
override suspend fun provideGlance(context: Context, id: GlanceId) {
val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
val repository = WidgetModelRepository.get(context)
您可能还需要添加以下导入项:
import com.google.android.samples.socialite.widget.model.WidgetModel
import com.google.android.samples.socialite.widget.model.WidgetModelRepository
import com.google.android.samples.socialite.widget.model.WidgetState.Loading
import androidx.glance.appwidget.GlanceAppWidgetManager
- 在
Content
可组合函数中,添加存储库和 widget ID 作为参数,并使用它们加载模型。更新Content
可组合项的函数签名,并添加以下代码行:
private fun Content(repository: WidgetModelRepository, widgetId: Int) {
val model = repository.loadModel(widgetId).collectAsState(Loading).value
- 如果 Android Studio 未自动添加以下导入项,请手动添加:
import androidx.compose.runtime.collectAsState
您还需要更新 provideGlance
,以将 widget ID 和存储库传递给 Content
。
将 provideGlance
替换为以下代码:
override suspend fun provideGlance(context: Context, id: GlanceId) {
val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
val repository = WidgetModelRepository.get(context)
provideContent {
GlanceTheme {
Content(repository, widgetId)
}
}
}
- 在
Content
可组合函数中,根据模型是否存在来确定要显示的状态。将Scaffold
和 widget 内容移至ZeroState
可组合项中,方法是将Scaffold
组件及其内容替换为以下 when 代码块:
when (model) {
is WidgetModel -> {Text("Hello World")}
else -> ZeroState(widgetId)
}
ZeroState
可组合项已包含在 com.google.android.samples.socialite.widget.ui
软件包的起始代码中。
- 如果 Android Studio 未自动导入
com.google.android.samples.socialite.widget.ui
软件包,请将以下代码添加到SociaLiteAppWidget
的“imports”部分。
import com.google.android.samples.socialite.widget.ui.ZeroState
- 如需查看更新,请重新运行应用,然后将 widget 的新副本添加到主屏幕。您会看到该 widget 显示了 ZeroState 组件和一个按钮。当您点击该按钮时,它将打开配置 activity,在下一节中,您将通过此 activity 更新 widget 状态。
配置 activity
查看 ZeroState 可组合函数。此函数位于 ZeroState.kt
文件内的 com.google.android.samples.socialite.widget.ui
软件包中。
@Composable fun ZeroState(widgetId: Int) { val widgetIdKey = ActionParameters.Key<Int>(AppWidgetManager.EXTRA_APPWIDGET_ID) Scaffold( titleBar = { TitleBar( modifier = GlanceModifier.clickable(actionStartActivity(MainActivity::class.java)), textColor = GlanceTheme.colors.onSurface, startIcon = ImageProvider(R.drawable.ic_launcher_monochrome), title = "SociaLite", ) }, backgroundColor = GlanceTheme.colors.widgetBackground, modifier = GlanceModifier.fillMaxSize(), ) { Box(modifier = GlanceModifier.fillMaxSize(), contentAlignment = Alignment.Center) { Button( text = "Select Favorite Contact", onClick = actionStartActivity<SociaLiteAppWidgetConfigActivity>( parameters = actionParametersOf(widgetIdKey to widgetId), ), ) } } }
Scaffold
可组合项已移至 ZeroState
可组合项中。TitleBar
具有 clickable
修饰符,用于打开 SociaLite 的主 activity。您的 ZeroState
使用 Glance Button
可组合项向用户显示号召性用语,点击该号召性用语会打开 SociaLiteAppWidgetConfigActivity
activity,并将 widget ID 作为 intent extra 包含在内。这两项操作都使用 Glance 的 actionStartActivity
便捷函数。如需详细了解 Action,请参阅处理用户互动。
- 了解如何使用
SociaLiteAppWidgetConfigActivity
更新 widget 的配置。此类也是 widget 的配置 activity。配置 activity 使用键AppWidgetManager.
*EXTRA_APPWIDGET_ID.
* 读取 intent 整数 extra。如需详细了解配置 activity,请参阅允许用户配置应用 widget。 - 在
SociaLiteAppWidgetConfigActivity
中,将ContactRow
onClick
属性中的TODO
替换为以下代码:
{
coroutineScope.launch {
widgetModelRepository.createOrUpdate(
WidgetModel(
appWidgetId,
contact.id,
contact.name,
contact.iconUri.toString(),
false,
),
)
SociaLiteAppWidget().updateAll(this@SociaLiteAppWidgetConfigActivity)
val resultValue = Intent().putExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetId,
)
setResult(RESULT_OK, resultValue)
finish()
}
}
如果 Android Studio 未自动添加以下包含项,请手动添加
import com.google.android.samples.socialite.widget.model.WidgetModel
import androidx.glance.appwidget.updateAll
import kotlinx.coroutines.launch
此代码块会更新您的 widget 状态。首先,它会借助存储库使用所选联系人的信息保存或更新 WidgetModel
。接下来,它会调用 updateAll
挂起函数。此函数会更新主屏幕上的所有 widget,并且可从应用内任何位置调用。最后,此代码块会设定配置 activity 的结果,以表明它已成功更新 widget。
- 运行并替换主屏幕上的 widget。您应该会看到新的零状态。
- 点击选择收藏的联系人。这会将您转到配置 activity。
- 选择相应联系人。 这会更新您的 widget。不过,该 widget 尚未显示您收藏的联系人,因为您将在下一部分中添加相应功能。
管理 widget 数据
- 打开应用检查工具,根据需要连接到进程,然后选择数据库检查器标签页以查看应用数据库的内容。
- 在 widget 中选择一个收藏的联系人,看看是否会更新为“Hello World”。返回到“应用检查”工具,您应该会看到一个 widget 模型标签页,其中包含一个 widget 条目。您可能需要刷新表格或按实时更新才能看到更改。
- 再添加一个 widget,然后再选择一个联系人。您可能需要按刷新表格或实时更新才能查看新模型。
- 移除该 widget 并注意,在移除 widget 后模型会保留在数据库中。
您可通过替换 onDeleted
来更新 SociaLiteAppWidgetReceiver
,以便在移除 widget 时清理数据库
如需清理孤立的 widget 模型,您可以调用 WidgetModelRepository.cleanupWidgetModels
。存储库类由 Hilt 管理,您需要使用依赖项注入来访问其实例。
- 在
SociaLiteAppWidgetReceiver
中,将AndroidEntryPoint
Hilt 注解添加到接收器类声明中,并注入WidgetModelRepository
实例。 - 在
onDeleted
的方法替换中调用WidgetModelRepository.cleanupWidgetModels
。
您的代码应如下所示:
package com.google.android.samples.socialite.widget
import android.content.Context
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
import com.google.android.samples.socialite.widget.model.WidgetModelRepository
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class SociaLiteAppWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = SociaLiteAppWidget()
@Inject
lateinit var repository: WidgetModelRepository
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
super.onDeleted(context, appWidgetIds)
repository.cleanupWidgetModels(context)
}
}
- 重新运行应用。当从主屏幕中移除 widget 时,您应该会在应用检查器中看到模型行已被移除。
5 添加联系人界面并在收到新消息时更新
您已进入本 Codelab 的最后阶段。在本部分中,您将为 widget 实现最终的联系人界面,并在有未读消息时更新该界面。
- 查看模型软件包中的
WidgetModelRepository
类。
此处包含 updateUnreadMessagesForContact
便捷方法;该方法会更新与联系人 ID 关联的 widget。
//Don't add this code.
fun updateUnreadMessagesForContact(contactId: Long, unread: Boolean) {
coroutineScope.launch {
widgetModelDao.modelsForContact(contactId).filterNotNull().forEach { model ->
widgetModelDao.update(
WidgetModel(model.widgetId, model.contactId, model.displayName, model.photo, unread)
)
SociaLiteAppWidget().updateAll(appContext)
}
}
}
此方法有两个参数:contactId
(要更新的联系人的 ID)和 unread
(未读消息状态的布尔值)。此方法使用 WidgetModelDao
查找显示此联系人的所有 widget 模型,并使用新的已读状态更新模型。然后,该函数会调用 Glance 提供的 SociaLiteAppWidget().updateAll
方法来更新用户主屏幕上的所有 widget。
现在,在已经了解了如何更新 widget 及其状态之后,您可以创建联系人界面、发送消息并观察其更新情况。为此,您需要在 widget 布局中使用 FavoriteContact
可组合项更新 SociaLiteAppWidget
。在此布局中,您还需要检查应显示 No new messages
还是 New Messages!
。
- 查看
com.google.android.samples.socialite.widget.ui
软件包中的FavoriteContact.kt
文件。
//Don't add this code.
@Composable
fun FavoriteContact(model: WidgetModel, onClick: Action) {
Column(
modifier = GlanceModifier.fillMaxSize().clickable(onClick)
.background(GlanceTheme.colors.widgetBackground).appWidgetBackground()
.padding(bottom = 8.dp),
verticalAlignment = Alignment.Vertical.Bottom,
horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
) {
Image(
modifier = GlanceModifier.fillMaxWidth().wrapContentHeight().defaultWeight()
.cornerRadius(16.dp),
provider = ImageProvider(model.photo.toUri()),
contentScale = ContentScale.Crop,
contentDescription = model.displayName,
)
Column(
modifier = GlanceModifier.fillMaxWidth().wrapContentHeight().padding(top = 4.dp),
verticalAlignment = Alignment.Vertical.Bottom,
horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
) {
Text(
text = model.displayName,
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 24.sp,
color = (GlanceTheme.colors.onSurface),
),
)
Text(
text = if (model.unreadMessages) "New Message!" else "No messages",
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
color = (GlanceTheme.colors.onSurface),
),
)
}
}
}
- 将
SociaLiteAppWidget
的Content
可组合项中的Text("Hello World")
替换为对FavoriteContact
可组合项的调用。
此可组合项将接受 WidgetModel 和由 actionStartActivity
Glance 函数创建的操作。
- 如果模型不是
WidgetModel
,请在ZeroState
之前添加对when
代码块的调用。
when (model) {
is WidgetModel -> FavoriteContact(model = model, onClick = actionStartActivity(
Intent(LocalContext.current.applicationContext, MainActivity::class.java)
.setAction(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.setData("https://socialite.google.com/chat/${model.contactId}".toUri()))
)
else -> ZeroState(widgetId)
}
- 如果 Android Studio 未自动添加以下导入项,请立即手动添加:
import com.google.android.samples.socialite.widget.ui.FavoriteContact
import androidx.glance.appwidget.action.actionStartActivity
import android.content.Intent
import com.google.android.samples.socialite.MainActivity
import androidx.core.net.toUri
- 运行应用。
- 选择一个收藏的联系人,发送消息,然后在对方回复之前立即退出应用。收到响应后,widget 的状态应发生变化。
- 点击该 widget 以打开聊天,并在退出到主屏幕时查看状态是否再次更新。
6 恭喜
您已成功完成此 Codelab,并学习了如何使用 Glance 编写 widget!您应该能够轻松创建一个可契合很多主屏幕、处理用户输入并自行更新的精美 widget。
如需获取 main
分支中的解决方案代码,请按以下步骤操作:
- 如果您已下载 SociaLite,请运行以下命令:
git checkout main
- 如果还未下载,您可再次下载该代码,以查看
main
分支:
git clone git@github.com:android/socialite.git