如何在Jetpack Glance中动态调整App Widget布局适配尺寸变化?
跨API级别处理Jetpack Glance Widget动态尺寸调整的可靠方案
方案一:结合自定义接收者与Glance更新机制
1. 重写Widget接收者处理尺寸变化
在自定义的GlanceAppWidgetReceiver中重写onAppWidgetOptionsChanged,获取最新Widget尺寸后通过协程触发Glance组件更新:
class WidgetReceiver : GlanceAppWidgetReceiver() { override val glanceAppWidget: GlanceAppWidget = AppWidget() override fun onAppWidgetOptionsChanged( context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, newOptions: Bundle ) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions) CoroutineScope(Dispatchers.IO).launch { glanceAppWidget.updateAppWidget(context, GlanceId.AppWidgetId(appWidgetId)) } } }
2. 在Glance组件中获取当前Widget尺寸
修改AppWidget类,通过currentAppWidgetOptions获取尺寸参数,统一处理不同API级别的宽度转换:
class AppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { val options = currentAppWidgetOptions(id) val widgetWidth = getWidgetWidth(context, options, id) provideContent { MyContent(context, widgetWidth) } } @Composable private fun MyContent(context: Context, widgetWidth: Int) { WidgetContent(widgetWidth) } private fun getWidgetWidth(context: Context, options: Bundle, id: GlanceId): Int { val appWidgetId = (id as? GlanceId.AppWidgetId)?.appWidgetId ?: return 0 val manager = AppWidgetManager.getInstance(context) return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) } else { val info = manager.getAppWidgetInfo(appWidgetId) info.minWidth } } }
3. 根据宽度动态调整布局
在WidgetContent中根据传入的宽度判断显示/隐藏组件:
@Composable fun WidgetContent(widgetWidth: Int) { Column(modifier = GlanceModifier.fillMaxSize()) { Text(text = "基础内容") // 自定义宽度阈值,根据实际布局调整 if (widgetWidth > context.resources.getDimensionPixelSize(R.dimen.widget_wide_threshold)) { Text(text = "宽屏专属内容") } } }
方案二:利用Glance状态管理存储尺寸信息
如果需要更灵活的状态同步,可将尺寸信息存入Glance的LocalState,实现布局自动响应:
1. 定义状态键
private const val WIDGET_WIDTH_KEY = "widget_width"
2. 在接收者中更新状态
override fun onAppWidgetOptionsChanged( context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int, newOptions: Bundle ) { super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions) CoroutineScope(Dispatchers.IO).launch { val glanceId = GlanceId.AppWidgetId(appWidgetId) glanceAppWidget.updateState(context, glanceId) { prefs -> val width = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) } else { appWidgetManager.getAppWidgetInfo(appWidgetId).minWidth } prefs.edit().putInt(WIDGET_WIDTH_KEY, width).apply() } glanceAppWidget.updateAppWidget(context, glanceId) } }
3. 在布局中读取状态并调整
@Composable private fun MyContent(context: Context) { val width = currentState<Int>(WIDGET_WIDTH_KEY) ?: 0 WidgetContent(width) }
关键注意事项
- 宽度阈值建议使用dp转像素的方式定义,适配不同屏幕密度
- 旧API中
minWidth为Widget最小宽度,若需实际显示宽度,可尝试读取OPTION_APPWIDGET_WIDTH(部分系统可能存在精度问题,需测试) - 所有Glance更新操作需在协程中执行,避免阻塞主线程
内容的提问来源于stack exchange,提问作者Yazan
相关产品推荐
相关产品推荐

