外观
主题 — HuaLuoTheme
颜色、字阶、形状、动效的唯一来源。在应用入口调用一次,整个界面树包在它里面即可。
基本用法
kotlin
HuaLuoTheme(darkTheme = isSystemInDarkTheme()) {
App()
}跟随设置里的深浅色选项(0 跟随系统 / 1 强制浅 / 2 强制深):
kotlin
val option by settings.darkModeOption.collectAsState()
HuaLuoTheme(darkTheme = resolveDarkTheme(option)) {
App()
}整份换配色:
kotlin
HuaLuoTheme(darkTheme = dark, colorScheme = myColorScheme) {
App()
}取弹簧动效规格:
kotlin
val spec = MaterialTheme.motionScheme.defaultSpatialSpec<Float>()
animateFloatAsState(targetValue = x, animationSpec = spec)参数
HuaLuoTheme
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
darkTheme | Boolean | — | 必传,没有默认值。 决定配色,也决定状态栏 / 导航栏图标的明暗 |
colorScheme | ColorScheme | defaultColorScheme(darkTheme) | 配色入口。整份传进来即可换肤 |
content | @Composable () -> Unit | — | 界面树 |
它内部已经帮你装好的东西(不要再自己加):MaterialExpressiveTheme(含 MotionScheme.expressive())、Shapes、Typography、LocalOverscrollFactory(过度滚动)、以及轻提示的渲染容器 PopupPrompt()。
defaultColorScheme
| 参数 | 类型 | 说明 |
|---|---|---|
darkTheme | Boolean | 返回 DefaultDarkScheme 或 DefaultLightScheme |
resolveDarkTheme
| 参数 | 类型 | 说明 |
|---|---|---|
darkModeOption | Int | 1 → false(浅色)、2 → true(深色)、其它 → isSystemInDarkTheme() |
三个可以直接引用的对象
| 名称 | 说明 |
|---|---|
DefaultLightScheme / DefaultDarkScheme | 两套内置 ColorScheme,顶层 val |
Shapes | 形状系统,见形状 |
Typography | 字阶,见字阶 |
要点
darkTheme必传。 它没有默认值 —— 显式写出来,别指望它自己跟系统。colorScheme和darkTheme是两件事:colorScheme管颜色,darkTheme管状态栏 / 导航栏图标的明暗。整份换配色时两个都要传对,否则会出现「浅色配色配浅色系统图标」这种读不清的组合。- 颜色没有第二个入口。 统一走
MaterialTheme.colorScheme.xxx,M3 那 45 个槽位就是全部约定 —— 别在组件之外硬编码Color(0xFF...)。 Color.kt里那两套 token(*Light/*Dark)是给主题构造用的,业务代码不该直接引用 —— 换肤时它们不跟着走。- 动效不要写死时长。 用
MaterialTheme.motionScheme里的规格(defaultSpatialSpec/defaultEffectsSpec),写死tween(300)就换不回来了。 - 只调一次。 嵌套第二层
HuaLuoTheme会把过度滚动工厂和轻提示容器也再挂一份,而且内层会整体覆盖外层配色。
说明
- 根节点是
MaterialExpressiveTheme,不是普通MaterialTheme。 它会把 motion scheme 默认设为MotionScheme.expressive(),并把 Expressive 的形状 / 字阶 / 色板接进来。Expressive 组件(ButtonGroup、SplitButton、FloatingActionButtonMenu、波浪LoadingIndicator等)只有挂在这个主题下才会拿到 expressive 的动效与形状默认值;挂在普通MaterialTheme下会退回标准 M3 观感,Expressive 组件会「名不副实」。 - 配色只有
ColorScheme一个入口。 需要什么语义就挑对应的 M3 槽位;M3 规范里没有的状态色(成功绿、警告琥珀这类)由用到它的组件自己写常量,不再往主题里塞第二套「扩展配色」—— 那套东西每加一个语义色就要多维护一组明暗映射,还把「换配色」从改一个文件变成改两个。 Color.kt只存纯配色 token(Material Theme Builder 的标准产物:明 / 暗各一套,外加 medium / high contrast 变体),它不构造任何ColorScheme—— 把 token 装成ColorScheme的活全在Theme.kt里。这样换配色只要替换Color.kt,一行代码都不用动;以后要加对比度档位、动态取色、节日主题,只改Theme.kt,不碰配色文件。- 两套
ColorScheme是顶层val,不是每次调用重建。ColorScheme是不可变对象,45 个槽位全量构造一次就够。放进HuaLuoTheme里每次重组 new 一份不仅浪费,还会让下游所有remember(colorScheme)/derivedStateOf缓存全部失效。 - 深色模式由调用方传入,主题不去读任何设置仓库。 原因:这个库是独立发布的 AAR,被多个 APK 使用,各边的设置类不同名 —— 库里去 bind 任意一边都会让另一边编译不过。
- 状态栏 / 导航栏图标的明暗是在
SideEffect里设的(isAppearanceLightStatusBars/isAppearanceLightNavigationBars = !darkTheme),预览模式下跳过。 defaultColorScheme的when是预留的扩展点:以后要插第三套配色就在那里加分支 ——Color.kt已经备好了 medium / high contrast 两组 token,照抄现有构造块的写法、把 token 名换成带MediumContrast/HighContrast后缀的那组即可。