You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:50:14