Jetpack Compose 入门系列(九):Compose 中的主题与 Material 3
学完上篇你已经知道如何用
LaunchedEffect、DisposableEffect等 API 处理副作用了。但一个 App 不只是能跑,还要看起来统一、专业,本篇解决一个问题:如何用 Material 3 管理颜色、字体、形状和深色模式。
一、为什么需要主题
前面几篇里,我们已经写过不少界面:按钮、列表、详情页、注册页、课程卡片。你可能会发现一个问题:如果每个组件都自己写颜色和字号,代码很快会变乱。
比如:
Text(
text = "课程标题",
color = Color(0xFF1E88E5),
fontSize = 22.sp
)
Button(
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF1E88E5)
),
onClick = {}
) {
Text(text = "开始学习")
}
这段代码能跑,但问题是:
- 蓝色到处写,后面换品牌色很麻烦。
- 字号到处写,页面风格容易不统一。
- 深色模式要一个个改,改到怀疑人生。
- 组件越多,重复代码越多。
在 XML 时代,我们会把颜色写进 colors.xml,把样式写进 styles.xml:
<color name="brand_primary">#1E88E5</color>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
<item name="colorPrimary">@color/brand_primary</item>
</style>
到了 Compose 里,对应的核心就是 MaterialTheme。
来做个对比:
| XML 时代 | Compose 时代 |
|---|---|
colors.xml | ColorScheme |
styles.xml | MaterialTheme |
TextAppearance | Typography |
shapeAppearance | Shapes |
Theme.MaterialComponents | MaterialTheme |
Material 3 的主题主要管三件事:
| 主题部分 | 负责什么 |
|---|---|
colorScheme | 颜色,比如主色、背景色、错误色 |
typography | 字体样式,比如标题、正文、标签 |
shapes | 形状,比如按钮、卡片圆角 |
用一句话概括:主题就是把全 App 共用的视觉规则集中管理起来。
flowchart TD
A[MaterialTheme] --> B[colorScheme 颜色]
A --> C[typography 字体]
A --> D[shapes 形状]
B --> E[Button / Card / TextField]
C --> F[Text]
D --> G[Card / Button / Surface]
关键点:不要在每个组件里到处写死颜色、字号和圆角。统一放进主题里,页面才会稳定、统一、好维护。
二、添加 Material 3 依赖
Material 3 是 Compose 里推荐使用的新一代 Material Design 组件库。
2.1 libs.versions.toml
[versions]
agp = "9.2.1"
kotlin = "2.2.10"
composeBom = "2026.02.01"
activity = "1.8.0"
[libraries]
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity" }
androidx-compose-material3 = { module = "androidx.compose.material3:material3" }
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
2.2 app/build.gradle.kts
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.compose.compiler)
}
android {
namespace = "com.example.materialtheme"
compileSdk = 36
defaultConfig {
applicationId = "com.example.materialtheme"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = "1.0"
}
buildFeatures {
compose = true
}
}
dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.ui.tooling.preview)
}
这段配置里发生了什么:
material3提供MaterialTheme、Button、Card、Scaffold、Surface等组件。- Compose BOM 统一管理 Compose 相关依赖版本。
ui-tooling-preview用来写@Preview预览界面。
如果你用的是 Material 3,就优先从
androidx.compose.material3包里导组件,不要和旧的androidx.compose.material混着用。
三、ColorScheme:统一管理颜色
Material 3 的颜色不再只是一两个 primary、accent,而是一整套 ColorScheme。
先定义一组颜色:
import androidx.compose.ui.graphics.Color
private val BrandBlue = Color(0xFF2563EB)
private val BrandBlueDark = Color(0xFF93C5FD)
private val BrandGreen = Color(0xFF16A34A)
private val BrandRed = Color(0xFFDC2626)
private val LightBackground = Color(0xFFF8FAFC)
private val DarkBackground = Color(0xFF0F172A)
然后定义浅色和深色主题:
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
private val LightColorScheme = lightColorScheme(
primary = BrandBlue,
onPrimary = Color.White,
secondary = BrandGreen,
onSecondary = Color.White,
error = BrandRed,
onError = Color.White,
background = LightBackground,
onBackground = Color(0xFF0F172A),
surface = Color.White,
onSurface = Color(0xFF0F172A)
)
private val DarkColorScheme = darkColorScheme(
primary = BrandBlueDark,
onPrimary = Color(0xFF172554),
secondary = Color(0xFF86EFAC),
onSecondary = Color(0xFF052E16),
error = Color(0xFFFCA5A5),
onError = Color(0xFF7F1D1D),
background = DarkBackground,
onBackground = Color(0xFFE2E8F0),
surface = Color(0xFF1E293B),
onSurface = Color(0xFFE2E8F0)
)
这段代码里发生了什么:
primary是主色,常用于主要按钮、重点信息。onPrimary是显示在主色上的内容颜色,比如按钮文字。secondary是辅助色,用于次要强调。background是页面背景色。surface是卡片、弹窗、导航栏这类表面的颜色。onSurface是显示在surface上的文字颜色。
常用颜色速查:
| 颜色字段 | 常见用途 |
|---|---|
primary | 主按钮、选中状态、重要操作 |
onPrimary | 主色上的文字或图标 |
secondary | 次要强调色 |
background | 页面背景 |
onBackground | 页面背景上的文字 |
surface | 卡片、底栏、弹窗背景 |
onSurface | surface 上的文字 |
error | 错误提示、危险操作 |
onError | 错误色上的文字 |
使用时不要直接写死颜色:
❌ 错误:
Text(
text = "课程标题",
color = Color(0xFF2563EB)
)
✅ 正确:
Text(
text = "课程标题",
color = MaterialTheme.colorScheme.primary
)
这样以后换主题色,只需要改 ColorScheme,不用满项目搜索 0xFF2563EB。
Material 3 颜色命名不是“这个颜色长什么样”,而是“这个颜色用在哪里”。比如
primary不是固定蓝色,它表示品牌主色。
补充:Material 3 还支持 Android 12 及以上的动态颜色,可以根据系统壁纸生成颜色方案。本文为了让示例更稳定、品牌色更明确,先使用手动定义的
LightColorScheme和DarkColorScheme。
四、Typography:统一管理字体样式
颜色统一之后,下一步就是字体。
在 XML 里,我们会用 TextAppearance 管理标题、正文、小字。
Compose 里用 Typography:
import androidx.compose.material3.Typography
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
private val DefaultTypography = Typography()
private val AppTypography = Typography(
headlineLarge = DefaultTypography.headlineLarge.copy(
fontSize = 30.sp,
fontWeight = FontWeight.Bold,
lineHeight = 38.sp
),
headlineMedium = DefaultTypography.headlineMedium.copy(
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
lineHeight = 32.sp
),
titleMedium = DefaultTypography.titleMedium.copy(
fontSize = 18.sp,
fontWeight = FontWeight.SemiBold,
lineHeight = 26.sp
),
bodyMedium = DefaultTypography.bodyMedium.copy(
fontSize = 15.sp,
lineHeight = 22.sp
),
labelLarge = DefaultTypography.labelLarge.copy(
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold
)
)
使用时这样写:
Text(
text = "课程商城",
style = MaterialTheme.typography.headlineMedium
)
Text(
text = "学习 Compose 主题和 Material 3 的基本用法。",
style = MaterialTheme.typography.bodyMedium
)
这段代码里发生了什么:
headlineMedium用于页面标题。titleMedium用于卡片标题。bodyMedium用于普通正文。labelLarge用于按钮文字、标签文字。- 页面不再关心具体字号,只关心“这是标题还是正文”。
常用字体速查:
| 字体样式 | 推荐用途 |
|---|---|
headlineLarge | 大标题、欢迎页标题 |
headlineMedium | 页面标题 |
titleMedium | 卡片标题、列表标题 |
bodyMedium | 正文说明 |
labelLarge | 按钮文字、标签 |
❌ 错误:
Text(
text = "课程标题",
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
✅ 正确:
Text(
text = "课程标题",
style = MaterialTheme.typography.titleMedium
)
字体样式的重点不是“少写几行代码”,而是让整个 App 的文字层级统一。标题像标题,正文像正文,别每个页面都自由发挥。
五、Shapes:统一管理圆角
Material 3 里,形状主要通过 Shapes 管理。
比如按钮、卡片、输入框的圆角,不建议到处写死:
Card(
shape = RoundedCornerShape(18.dp)
) {
// ...
}
更推荐统一定义:
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp
private val AppShapes = Shapes(
extraSmall = RoundedCornerShape(6.dp),
small = RoundedCornerShape(10.dp),
medium = RoundedCornerShape(16.dp),
large = RoundedCornerShape(24.dp),
extraLarge = RoundedCornerShape(32.dp)
)
使用:
Card(
shape = MaterialTheme.shapes.medium
) {
Text(
text = "课程卡片",
modifier = Modifier.padding(16.dp)
)
}
常用形状速查:
| 形状 | 推荐用途 |
|---|---|
extraSmall | 小标签、Chip |
small | 小按钮、小输入区域 |
medium | 普通卡片、输入框 |
large | 大卡片、底部弹窗 |
extraLarge | 强视觉容器 |
圆角也是设计语言的一部分。一个页面 8dp、另一个页面 23dp、第三个页面 12dp,看起来就会很散。
六、封装 AppTheme:让主题真正生效
定义完颜色、字体、形状之后,需要把它们放进一个统一的 Theme 函数。
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
@Composable
fun CourseAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) {
DarkColorScheme
} else {
LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = AppTypography,
shapes = AppShapes,
content = content
)
}
然后在 MainActivity 中使用:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CourseAppTheme {
CourseHomeScreen()
}
}
}
}
这段代码里发生了什么:
isSystemInDarkTheme()根据系统设置判断是否深色模式。darkTheme为 true 时使用DarkColorScheme。darkTheme为 false 时使用LightColorScheme。MaterialTheme把颜色、字体、形状提供给内部所有 Composable。- 内部组件可以通过
MaterialTheme.colorScheme、MaterialTheme.typography、MaterialTheme.shapes获取主题值。
主题传递关系如下:
flowchart TD
A[CourseAppTheme] --> B[MaterialTheme]
B --> C[CourseHomeScreen]
C --> D[CourseCard]
C --> E[Button]
C --> F[Text]
D --> G[MaterialTheme.colorScheme.surface]
E --> H[MaterialTheme.colorScheme.primary]
F --> I[MaterialTheme.typography]
关键点:
MaterialTheme要包在 App 根部。这样内部页面和组件才能拿到统一主题。
七、常见错误:别把主题写散了
7.1 不要到处写死颜色
❌ 错误:
Button(
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF2563EB)
),
onClick = {}
) {
Text(text = "开始")
}
✅ 正确:
Button(
onClick = {}
) {
Text(text = "开始")
}
Material 3 的 Button 默认就会使用 MaterialTheme.colorScheme.primary。
Material 3 组件默认会从主题里读取合适的颜色,所以很多时候不用手动写 colors = ...。只有当组件语义和默认样式不一致时,才需要覆盖。
如果确实要自定义,也应该从主题里取:
Button(
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondary
),
onClick = {}
) {
Text(text = "次要操作")
}
能用组件默认主题就先用默认主题,只有明确需要区分时再覆盖颜色。
7.2 不要在每个 Text 里手写字号
❌ 错误:
Text(
text = "页面标题",
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
✅ 正确:
Text(
text = "页面标题",
style = MaterialTheme.typography.headlineMedium
)
这样以后标题整体变大或变小,只改主题就行。
7.3 不要只做浅色,不管深色模式
❌ 错误:
MaterialTheme(
colorScheme = LightColorScheme,
content = content
)
✅ 正确:
val colorScheme = if (darkTheme) {
DarkColorScheme
} else {
LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
content = content
)
深色模式不是最后再补的功能。主题一开始就把 Light 和 Dark 分开,后面会省很多事。
八、综合实战:课程首页主题 Demo
下面我们把前面的知识串起来,做一个课程首页:
- 支持浅色 / 深色主题切换
- 使用统一品牌色
- 使用统一字体层级
- 使用统一圆角
- 卡片、按钮、标签都从
MaterialTheme取值
完整代码如下:
package com.example.materialtheme
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Shapes
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.Typography
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CourseThemeDemoApp()
}
}
}
private val BrandBlue = Color(0xFF2563EB)
private val BrandBlueDark = Color(0xFF93C5FD)
private val BrandGreen = Color(0xFF16A34A)
private val BrandRed = Color(0xFFDC2626)
private val LightBackground = Color(0xFFF8FAFC)
private val DarkBackground = Color(0xFF0F172A)
private val LightColorScheme = lightColorScheme(
primary = BrandBlue,
onPrimary = Color.White,
secondary = BrandGreen,
onSecondary = Color.White,
error = BrandRed,
onError = Color.White,
background = LightBackground,
onBackground = Color(0xFF0F172A),
surface = Color.White,
onSurface = Color(0xFF0F172A)
)
private val DarkColorScheme = darkColorScheme(
primary = BrandBlueDark,
onPrimary = Color(0xFF172554),
secondary = Color(0xFF86EFAC),
onSecondary = Color(0xFF052E16),
error = Color(0xFFFCA5A5),
onError = Color(0xFF7F1D1D),
background = DarkBackground,
onBackground = Color(0xFFE2E8F0),
surface = Color(0xFF1E293B),
onSurface = Color(0xFFE2E8F0)
)
private val DefaultTypography = Typography()
private val AppTypography = Typography(
headlineLarge = DefaultTypography.headlineLarge.copy(
fontSize = 30.sp,
fontWeight = FontWeight.Bold,
lineHeight = 38.sp
),
headlineMedium = DefaultTypography.headlineMedium.copy(
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
lineHeight = 32.sp
),
titleMedium = DefaultTypography.titleMedium.copy(
fontSize = 18.sp,
fontWeight = FontWeight.SemiBold,
lineHeight = 26.sp
),
bodyMedium = DefaultTypography.bodyMedium.copy(
fontSize = 15.sp,
lineHeight = 22.sp
),
labelLarge = DefaultTypography.labelLarge.copy(
fontSize = 14.sp,
fontWeight = FontWeight.SemiBold
)
)
private val AppShapes = Shapes(
extraSmall = RoundedCornerShape(6.dp),
small = RoundedCornerShape(10.dp),
medium = RoundedCornerShape(16.dp),
large = RoundedCornerShape(24.dp),
extraLarge = RoundedCornerShape(32.dp)
)
@Composable
private fun CourseThemeDemoApp() {
val systemDarkTheme = isSystemInDarkTheme()
var useDarkTheme by rememberSaveable {
mutableStateOf(systemDarkTheme)
}
CourseAppTheme(
darkTheme = useDarkTheme
) {
CourseHomeScreen(
useDarkTheme = useDarkTheme,
onThemeChange = {
useDarkTheme = it
}
)
}
}
@Composable
private fun CourseAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) {
DarkColorScheme
} else {
LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = AppTypography,
shapes = AppShapes,
content = content
)
}
@Composable
private fun CourseHomeScreen(
useDarkTheme: Boolean,
onThemeChange: (Boolean) -> Unit
) {
Scaffold(
containerColor = MaterialTheme.colorScheme.background
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column {
Text(
text = "课程商城",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground
)
Text(
text = "统一主题,让界面更像一个产品",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground
)
}
Switch(
checked = useDarkTheme,
onCheckedChange = onThemeChange
)
}
CourseSummaryCard()
CourseCard(
title = "Compose 主题与 Material 3",
description = "学习颜色、字体、形状和深色模式的统一管理。",
tag = "主题"
)
CourseCard(
title = "Material 3 组件实战",
description = "用 Button、Card、Surface 组合出统一风格界面。",
tag = "组件"
)
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
Button(
onClick = {}
) {
Text(text = "开始学习")
}
OutlinedButton(
onClick = {}
) {
Text(text = "查看大纲")
}
}
}
}
}
@Composable
private fun CourseSummaryCard() {
Surface(
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary,
shape = MaterialTheme.shapes.large
) {
Column(
modifier = Modifier.padding(20.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = "本周推荐",
style = MaterialTheme.typography.labelLarge
)
Text(
text = "把主题系统搭好,后面写页面会轻松很多。",
style = MaterialTheme.typography.bodyMedium
)
}
}
}
@Composable
private fun CourseCard(
title: String,
description: String,
tag: String
) {
Card(
modifier = Modifier.fillMaxWidth(),
shape = MaterialTheme.shapes.medium,
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.onSurface
),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Text(
text = title,
style = MaterialTheme.typography.titleMedium
)
Text(
text = description,
style = MaterialTheme.typography.bodyMedium
)
Text(
text = tag,
modifier = Modifier
.background(
color = MaterialTheme.colorScheme.secondary,
shape = MaterialTheme.shapes.extraSmall
)
.padding(horizontal = 10.dp, vertical = 4.dp),
color = MaterialTheme.colorScheme.onSecondary,
style = MaterialTheme.typography.labelLarge
)
}
}
}
这里的 useDarkTheme 初始值来自 isSystemInDarkTheme(),所以第一次进入页面时会跟随系统深色模式;用户点击 Switch 后,再使用用户手动选择的主题。
真实项目中,用户选择的主题通常会保存到 DataStore,下次启动时继续使用。这里为了聚焦主题本身,先用 rememberSaveable 保存页面内状态。
这份 Demo 中,主题数据流是这样的:
flowchart TD
A[Switch 切换主题] --> B[useDarkTheme 状态变化]
B --> C[CourseAppTheme 选择 ColorScheme]
C --> D[MaterialTheme 提供主题]
D --> E[CourseHomeScreen]
E --> F[CourseSummaryCard]
E --> G[CourseCard]
F --> H[读取 colorScheme / typography / shapes]
G --> I[读取 colorScheme / typography / shapes]
实战知识点对应表
| 实战中的效果 | 使用的 API | 对应章节 |
|---|---|---|
| 品牌色统一管理 | lightColorScheme / darkColorScheme | 三 |
| 标题和正文统一样式 | Typography | 四 |
| 卡片和标签统一圆角 | Shapes | 五 |
| 全局主题封装 | CourseAppTheme | 六 |
| 深色模式切换 | darkTheme + MaterialTheme | 六、八 |
| 组件从主题取值 | MaterialTheme.colorScheme 等 | 三、八 |
这就是主题系统的价值:页面组件不用知道具体颜色、字号、圆角是多少,只需要知道自己在用哪种语义角色。
九、Material 3 主题速查表
| 你想做什么 | 推荐写法 |
|---|---|
| 设置主色 | lightColorScheme(primary = ...) |
| 设置深色主题 | darkColorScheme(...) |
| 获取主色 | MaterialTheme.colorScheme.primary |
| 获取页面背景色 | MaterialTheme.colorScheme.background |
| 获取卡片色 | MaterialTheme.colorScheme.surface |
| 设置页面标题样式 | MaterialTheme.typography.headlineMedium |
| 设置卡片标题样式 | MaterialTheme.typography.titleMedium |
| 设置正文样式 | MaterialTheme.typography.bodyMedium |
| 设置卡片圆角 | MaterialTheme.shapes.medium |
| 封装全局主题 | MaterialTheme(colorScheme, typography, shapes) |
十、总结
本篇你学到了 Compose 中主题与 Material 3 的核心用法:
- 主题的意义:把颜色、字体、形状这些全局视觉规则集中管理,避免写散
ColorScheme:用语义化颜色管理主色、背景色、卡片色、错误色- 深色模式:用
lightColorScheme和darkColorScheme分别定义浅色与深色主题 Typography:统一标题、正文、标签等字体层级Shapes:统一按钮、卡片、标签等组件圆角MaterialTheme:在 App 根部提供主题,让内部组件统一读取- 组件默认主题:Material 3 组件默认会读取主题,不需要到处手写颜色
核心原则:不要让每个页面自己决定颜色、字号和圆角。主题先统一,组件再复用,App 才会像一个整体。
下一篇我们将学习 Paging 3 分页加载——如何在真实列表场景中处理分页加载、加载更多、刷新、空状态和错误重试。
如果你在学习过程中有任何疑问,欢迎在评论区留言,我会尽可能回复。
系列文章:
- Jetpack Compose 入门系列(一):从零搭建到基础控件使用
- Jetpack Compose 入门系列(二):布局到 State 的使用
- Jetpack Compose 入门系列(三):MVVM + 协程 实现网络请求列表
- Jetpack Compose 入门系列(四):动画基本使用
- Jetpack Compose 入门系列(五):自定义布局与 ConstraintLayout
- Jetpack Compose 入门系列(六):Navigation 3 页面导航
- Jetpack Compose 入门系列(七):ViewModel 与界面状态管理
- Jetpack Compose 入门系列(八):Compose 中的副作用处理
- Jetpack Compose 入门系列(九):Compose 中的主题与 Material 3(本文)