Jetpack架构组件学习(6)——使用Glance实现桌面小组件

原文地址: Jetpack架构组件学习(6)——使用Glance实现桌面小组件-Stars-One的杂货小窝

公司陆续整了几个Compose写的app,有个小组件的功能,顺便试了下Jetpack库里的Glance框架

感觉与原来的Remoteview差点意思,不过点击事件的使用比Remoteview要方便不少

PS: 如果想看Remoteview实现的小组件,可以参考我的此文Android 桌面小组件使用-Stars-One的杂货小窝

基本使用

1.添加依赖

添加Glance依赖:

// For AppWidgets support
 implementation "androidx.glance:glance-appwidget:1.1.0"
 // For interop APIs with Material 3
 implementation "androidx.glance:glance-material3:1.1.0"
 // For interop APIs with Material 2
 implementation "androidx.glance:glance-material:1.1.0"

2.正常的相关设置

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="2"
 android:targetCellHeight="2"
 android:minWidth="250dp"
 android:minHeight="250dp"
 android:updatePeriodMillis="0"
 android:initialLayout="@layout/glance_default_loading_layout"
 tools:targetApi="s">
</appwidget-provider>

清单文件配置:

<receiver android:name=".appwidgets.MyAppWidgetReceiver"
	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>

3.创建widget对象和实现界面

需要注意的几点:

  1. 界面的Row,Column,Text等,注意要使用Glance的包下的,否则会无法正常显示界面

官方也是说明了,Row,Box,Column实际最后创建的对象对应的Linearlayout和Framelayout

  1. 点击跳转的对应actionStartActivity方法,实际是返回一个Action对象 通过GlanceModifier.clickable(actionStartActivity(MainActivity::class.java))进行对应跳转

除了activity外,还能启动Service,BoardCast,详见此文档处理用户互动 | Jetpack Compose | Android Developers

  1. 关于背景圆角的方法,目前采用Box里面套一个Image和具体内容实现,Image去加载我们drawable里的矢量图对象(shape的那种)来实现
  2. remember在里面可用,但如果结合animateColorAsState这种动画效果,实际上并没有效果(只是单纯的变更,没有中间过渡过程)
class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
 //MyAppWidget里就是类似我们remoteview的创建
 override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
}
class MyAppWidget : GlanceAppWidget() {
 override suspend fun provideGlance(context: Context, id: GlanceId) {
 // In this method, load data needed to render the AppWidget.
 // Use `withContext` to switch to another thread for long running
 // operations.
 provideContent {
 val upSpeed by DataRespotiy.upSpeed.asFlow().collectAsState(initial = 0L)
 val downloadSpeed by DataRespotiy.downloadSpeed.asFlow().collectAsState(initial = 0L)
 Box(GlanceModifier.fillMaxSize()) {
 Image(provider = ImageProvider(R.drawable.app_widget_bg), contentDescription = null, modifier = GlanceModifier.fillMaxSize())
 Column(GlanceModifier.fillMaxSize()) {
 Spacer(GlanceModifier.height(28.dp))
 Row(GlanceModifier.fillMaxWidth().padding(horizontal = 20.dp)) {
 androidx.glance.Image(provider = ImageProvider(R.mipmap.logo), contentDescription = null, modifier = GlanceModifier.size(108.dp))
 Spacer(modifier = GlanceModifier.width(24.dp))
 Column(GlanceModifier.defaultWeight()) {
 Row(modifier = GlanceModifier.wrapContentHeight(), horizontalAlignment = Alignment.End, verticalAlignment = Alignment.Vertical.CenterVertically) {
 Text(text = "${upSpeed} Kb/s", style = TextStyle(color = ColorProvider(APP_Primary_color), fontSize = 22.sp))
 Spacer(modifier = GlanceModifier.width(4.dp))
 androidx.glance.Image(provider = ImageProvider(R.drawable.icon_upload_widget), contentDescription = null, modifier = GlanceModifier.size(32.dp))
 }
 Spacer(modifier = GlanceModifier.height(18.dp))
 Row(modifier = GlanceModifier, horizontalAlignment = Alignment.End, verticalAlignment = Alignment.Vertical.CenterVertically) {
 Text(text = "${downloadSpeed} Kb/s", style = TextStyle(color = ColorProvider(APP_Bigfile_color), fontSize = 22.sp))
 Spacer(modifier = GlanceModifier.width(4.dp))
 androidx.glance.Image(provider = ImageProvider(R.drawable.icon_down_widget), contentDescription = null, modifier = GlanceModifier.size(32.dp))
 }
 }
 }
 Spacer(GlanceModifier.height(28.dp))
 Box(modifier = GlanceModifier.fillMaxWidth().defaultWeight()) {
 Image(provider = ImageProvider(R.drawable.app_widget_bg1), contentDescription = null, modifier = GlanceModifier.fillMaxSize())
 Row(
 modifier = GlanceModifier.fillMaxSize()
 .padding(horizontal = 20.dp,16.dp), horizontalAlignment = Alignment.CenterHorizontally
 ) {
 val modifier = GlanceModifier.defaultWeight()
 //todo 不同的item类型
 repeat(3) { index ->
 Row(modifier, horizontalAlignment = Alignment.CenterHorizontally, verticalAlignment = Alignment.Vertical.CenterVertically) {
 androidx.glance.Image(
 provider = ImageProvider(R.drawable.icon_net_test), contentDescription = null, modifier = GlanceModifier
 .size(108.dp)
 .clickable(actionStartActivity(MainActivity::class.java))
 )
 }
 Spacer(GlanceModifier.width(20.dp))
 }
 }
 }
 }
 }
 }
 }
}

其他补充

更新小组件方法:

val manager = GlanceAppWidgetManager(application)
val widget = MyAppWidget()
val glanceIds = manager.getGlanceIds(widget.javaClass)
glanceIds.forEach { glanceId ->
	widget.update(application, glanceId)
}
//第二种方式(实际上和上面的方法是一样的,下面这个是官方给我们封装的另外个方法)
MyAppWidget().updateAll(application)

参考

作者:Stars-one原文地址:https://www.cnblogs.com/stars-one/p/18686180

%s 个评论

要回复文章请先登录注册