MaterialTheme
Compose 中除了基础布局和 BasicText(这个基本上不用)之外常用的组件都在 M2/M3 依赖中,这些组件样式都基于 MaterialTheme 开发设计。
M2 包含 color、typography、shape 三个部分。
MaterialTheme(
colors = …,
typography = …,
shapes = …
) {
// app content
M3 暂时还不包含 shape,但 M3 中有基于主屏墙纸的动态颜色功能。
MaterialTheme(
colorScheme = …,
typography = …
// Updates to shapes coming soon
) {
// M3 app conten
}
// Dynamic color is available on Android 12+
val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colorScheme = when {
dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
项目中用的是 M3 组件,这里我们就着重说一下 M3 主题,详情见官网。
color
定义一套颜色方案 ,由设计人员提供或者使用M3 官方提供了 Material Theme Builder ,选一下 Core colors 自动生成 Light / Dark Themem ,右上角可以直接导出 kt 文件。
typography
M3 / M2 默认字体样式
Typography 函数用来修改默认的字体样式:
val KarlaFontFamily = FontFamily(
Font(R.font.karla_regular),
Font(R.font.karla_bold, FontWeight.Bold)
)
val AppTypography = Typography(
bodyLarge = TextStyle(
fontFamily = KarlaFontFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.15.sp
),
// titleMedium, labelSmall, etc.
MaterialTheme 工作原理
我们以 CenterAlignedTopAppBar 标题颜色为例
@Composable
fun CenterAlignedTopAppBar(
colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors()
)
@Composable
fun centerAlignedTopAppBarColors(
titleContentColor: Color =
TopAppBarSmallCenteredTokens.HeadlineColor.toColor()
)
internal object TopAppBarSmallCenteredTokens {
val HeadlineColor = ColorSchemeKeyTokens.OnSurfac
}
{
ProvideTextStyle(value = titleTextStyle) {
CompositionLocalProvider(
LocalContentColor provides titleContentColor.copy(alpha = titleAlpha)
content = title
)
}
}
可以看出标题颜色使用主题中的 OnSurface ,将这个颜色设置给 LocalContentColor 并包裹标题组件,这样标题组件中获取的 LocalContentColor 就是主题中的 OnSurface 。再以标题是 Text 为例
val textColor = color.takeOrElse {
style.color.takeOrElse {
LocalContentColor.current
}
}
字体颜色默认是 LocalContentColor 。
CompositionLocal + MaterailTheme 就是以这种方法完成了 UI 样式的统一设置。
MaterialTheme 拓展
间距也是我们常用的属性,M2/M3 中都没有这一属性,下面我们基于 CompositionLocal 来对 MaterialTheme 进行拓展。
添加数据类 Spacing 同时声明对应的 CompositionLocal
data class Spacing(
val normalPadding:Dp = 16.dp,
val largePadding:Dp = 28.dp,
val smallPadding:Dp = 8.dp,
//todo add
)
val LocalSpacing = staticCompositionLocalOf<Spacing> { error("Spacing not provide")
使用 CompositionLocalProvider 包裹 MaterialTheme 提供 LocalSpacing 的值
CompositionLocalProvider( LocalSpacing provides Spacing()) {
MaterialTheme(
colorScheme = colorScheme,
typography = Typography
content = content
)
}
仿照 MaterialTheme 定义 object WanAndroidTheme 单例添加 spacing 属性
object WanAndroidTheme{
val colorScheme: ColorScheme
@Composable
@ReadOnlyComposable
get() = MaterialTheme.colorScheme
val typography: Typography
@Composabl
@ReadOnlyComposable
get() = MaterialTheme.typography
val shapes: Shapes
@Composable
@ReadOnlyComposable
get() = MaterialTheme.shapes
val spacing: Spacing
@Composable
@ReadOnlyComposable
get() = LocalSpacing.current
}
在 Composable 函数中使用 spacing
@Composable
fun UiProfile() {
Text(
modifier = Modifier.padding(horizontal = WanAndroidTheme.spacing.largePadding), text = "我的"
}