用途:为 Material 配色方案未覆盖的“应用自有语义颜色”提供统一归属,避免把十六进制字面量散落在各处。Material 配色方案覆盖 surface、container、primary/secondary/tertiary、error 及 on… 配对等角色,但不覆盖含义由应用定义的颜色,例如表示“已喜欢”的粉色、正在朗读文本中当前行的强调色、shimmer 在两种色调之间的扫过、压暗图像的遮罩层。
主要能力:以 @Immutable data class 定义 AppColors,包含 favorite、lyricActive、shimmerBackground、shimmerLine、overlay、overlayHeavy 等字段;把暗色实例提升为顶层 val,再用 copy() 只改动有差异的字段派生浅色实例(示例中遮罩在两种主题下都保持深色,因为它覆盖的图像内容始终是浅色);通过 staticCompositionLocalOf 创建 LocalAppColors,并在主题中以 CompositionLocalProvider 与 ColorScheme 一起提供,同时提供 LocalIsDarkTheme 布尔本地值。
使用方式:在主题 composable 中用 CompositionLocalProvider(LocalAppColors provides if (isDark) DarkAppColors else LightAppColors, LocalIsDarkTheme provides isDark, content = content) 发布令牌;消费方直接读取 CompositionLocal。资料强调 static 与 dynamic 的差别是真实差异而非风格偏好:在 androidx.compose.runtime:runtime-desktop:1.12.0-alpha02 上,staticCompositionLocalOf 的 StaticProvidableCompositionLocal 构建 ProvidedValue 时使用 null mutation policy、null backing state 和 isDynamic=false,而 compositionLocalOf 的 DynamicProvidableCompositionLocal 传入策略并将该标志设为 true;因此静态本地值没有可供读者订阅的状态,改动它必须使 provider 下所有内容失效,动态本地值由状态支撑、只使读取它的 composable 失效。主题令牌几乎不变(只在主题切换时变)且被数百处读取,适合 static;频繁变化且读取点少的值(滚动偏移、正在播放项)适合 dynamic。资料还给出用 javap 检查两个 defaultProvidedValue$runtime 方法体尾部的命令。
陷阱与限制(资料所述):@Immutable 主要依赖开发者承诺,若含 var、可变集合或不稳定的第三方类型,注解即为谎言,基于它做出的跳过决策会静默出错;应把令牌实例提升为顶层 val,不要在主题 composable 内构建对象;用 copy() 派生第二主题以表达意图;不要重复已有 Material 角色(surface 层级、outline、error、primary/secondary 强调色),能从种子派生的就应作为角色;默认值应是真实回退(预览、测试和未包在主题中的组合根会用到),除非希望预览崩溃,否则应设为主集合而非抛异常的 lambda;应发布 LocalIsDarkTheme 而不是让每个消费方重新推导主题(系统模式与子树强制模式可能不同),着色或模糊的平台效果必须读取该本地值而非 isSystemInDarkTheme();绝不要在无 key 的 remember 中捕获令牌(如 remember { colors.favorite } 会冻结首个主题值,只有不离开屏幕切换主题时才暴露),应把令牌作为 key 或直接读取;淘汰旧颜色应用 @Deprecated 标注并注明唯一剩余用处,而非直接删除。
核验方式:资料提供多条 grep 命令,分别列出所有声明及其工厂(对照 static/dynamic 规则)、检查每个令牌持有类的上下文两行是否带 @Immutable、统计 theme 包外重复出现的十六进制字面量(出现次数大于 1 的应归入令牌类或方案,注意大小写会被 uniq 分开计数)、查找被无 key 的 remember 冻结的令牌(期望无输出);并建议在停留在某屏幕时切换主题(而非重启应用)用肉眼确认行为差异。
适用场景:使用 Jetpack Compose 的 Android/Kotlin 项目,需要在多主题下统一管理应用自有颜色语义。平台、收费、价格、效果等信息暂未提供。