Android 开发入门教程(第三十五篇):Compose 中的 Material Design 3 —— 构建现代化 UI 的完整组件库 引言Material Design 与 Compose 的完美结合Material Design 是 Google 于 2014 年推出的设计语言旨在为跨平台设备提供统一的视觉和交互体验。经过近十年的演进Material Design 已经发展到了第三个版本Material Design 3也称作 Material You。Material Design 3 的核心特性包括动态配色系统可以根据壁纸自动生成配色方案组件更新按钮、卡片、导航栏等组件样式升级无障碍增强更高的对比度要求更好的触摸目标自适应布局对不同屏幕尺寸更好的支持Jetpack Compose 从一开始就深度整合了 Material Design。Compose 的material3库提供了完整的 Material Design 3 组件实现包括颜色系统、排版、形状以及各种 UI 组件。在本篇中我们将系统介绍 Compose Material Design 3 的各个组件MaterialTheme 与颜色系统排版系统Typography形状系统Shapes按钮系列Button、TextButton、OutlinedButton、IconButton导航组件TopAppBar、BottomNavigation、NavigationRail容器组件Card、Surface数据展示组件Badge、Chip、Switch、Slider、Checkbox、RadioButton反馈组件Snackbar、Dialog、ProgressIndicator注意本篇假设你已经熟悉 Compose 基础。Material 3 组件在androidx.compose.material3包中。一、MaterialTheme 与颜色系统1.1 基本主题设置kotlinimport androidx.compose.material3.MaterialTheme import androidx.compose.material3.lightColorScheme import androidx.compose.material3.darkColorScheme Composable fun MyAppTheme( darkTheme: Boolean isSystemInDarkTheme(), content: Composable () - Unit ) { val colorScheme if (darkTheme) { darkColorScheme( primary Color(0xFFBB86FC), secondary Color(0xFF03DAC6), tertiary Color(0xFFFFB74D), background Color(0xFF121212), surface Color(0xFF1E1E1E) ) } else { lightColorScheme( primary Color(0xFF6200EE), secondary Color(0xFF03DAC6), tertiary Color(0xFFFF9800), background Color(0xFFFFFFFF), surface Color(0xFFFFFFFF) ) } MaterialTheme( colorScheme colorScheme, typography MyTypography, shapes MyShapes, content content ) }1.2 使用主题颜色kotlinComposable fun ThemedComponent() { // 使用主题中的颜色 Surface( color MaterialTheme.colorScheme.primaryContainer, contentColor MaterialTheme.colorScheme.onPrimaryContainer ) { Text( text 这是一个容器, modifier Modifier.padding(16.dp) ) } Button( onClick { }, colors ButtonDefaults.buttonColors( containerColor MaterialTheme.colorScheme.secondary ) ) { Text(次要按钮) } }1.3 MaterialTheme 提供的颜色颜色角色用途primary主要品牌色onPrimary在 primary 上方的元素颜色primaryContainer主要色容器secondary次要品牌色onSecondary在 secondary 上方的元素颜色tertiary第三品牌色background背景色surface表面色error错误色surfaceVariant表面变体色二、排版系统kotlinimport androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp val MyTypography Typography( displayLarge TextStyle( fontFamily FontFamily.Default, fontWeight FontWeight.Bold, fontSize 57.sp, lineHeight 64.sp ), displayMedium TextStyle( fontWeight FontWeight.Bold, fontSize 45.sp, lineHeight 52.sp ), displaySmall TextStyle( fontWeight FontWeight.Bold, fontSize 36.sp, lineHeight 44.sp ), headlineLarge TextStyle( fontWeight FontWeight.SemiBold, fontSize 32.sp, lineHeight 40.sp ), headlineMedium TextStyle( fontWeight FontWeight.SemiBold, fontSize 28.sp, lineHeight 36.sp ), headlineSmall TextStyle( fontWeight FontWeight.SemiBold, fontSize 24.sp, lineHeight 32.sp ), bodyLarge TextStyle( fontWeight FontWeight.Normal, fontSize 16.sp, lineHeight 24.sp ), bodyMedium TextStyle( fontWeight FontWeight.Normal, fontSize 14.sp, lineHeight 20.sp ), bodySmall TextStyle( fontWeight FontWeight.Normal, fontSize 12.sp, lineHeight 16.sp ), labelLarge TextStyle( fontWeight FontWeight.Medium, fontSize 14.sp, lineHeight 20.sp ), labelMedium TextStyle( fontWeight FontWeight.Medium, fontSize 12.sp, lineHeight 16.sp ) ) Composable fun TypographyDemo() { Column { Text(Display Large, style MaterialTheme.typography.displayLarge) Text(Display Medium, style MaterialTheme.typography.displayMedium) Text(Display Small, style MaterialTheme.typography.displaySmall) Text(Headline Large, style MaterialTheme.typography.headlineLarge) Text(Body Large, style MaterialTheme.typography.bodyLarge) Text(Body Medium, style MaterialTheme.typography.bodyMedium) Text(Label Large, style MaterialTheme.typography.labelLarge) } }三、形状系统kotlinimport androidx.compose.material3.Shapes import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.ui.unit.dp val MyShapes Shapes( extraSmall RoundedCornerShape(4.dp), small RoundedCornerShape(8.dp), medium RoundedCornerShape(12.dp), large RoundedCornerShape(16.dp), extraLarge RoundedCornerShape(28.dp) ) Composable fun ShapesDemo() { Column { Surface( shape MaterialTheme.shapes.small, modifier Modifier.size(80.dp), color MaterialTheme.colorScheme.primary ) { // 小圆角内容 } Surface( shape MaterialTheme.shapes.medium, modifier Modifier.size(80.dp), color MaterialTheme.colorScheme.secondary ) { // 中圆角内容 } Card( shape MaterialTheme.shapes.large, modifier Modifier.fillMaxWidth() ) { Text(大圆角卡片, modifier Modifier.padding(16.dp)) } } }四、按钮系列4.1 FilledButton填充按钮kotlinComposable fun FilledButtonExample() { Button( onClick { }, modifier Modifier.fillMaxWidth() ) { Text(填充按钮) } }4.2 OutlinedButton边框按钮kotlinComposable fun OutlinedButtonExample() { OutlinedButton( onClick { }, modifier Modifier.fillMaxWidth() ) { Text(边框按钮) } }4.3 TextButton文本按钮kotlinComposable fun TextButtonExample() { TextButton( onClick { }, modifier Modifier.fillMaxWidth() ) { Text(文本按钮) } }4.4 IconButton图标按钮kotlinComposable fun IconButtonExample() { IconButton( onClick { } ) { Icon(Icons.Default.Favorite, contentDescription 收藏) } }4.5 FilledTonalButton色调按钮kotlinComposable fun TonalButtonExample() { FilledTonalButton( onClick { }, modifier Modifier.fillMaxWidth() ) { Text(色调按钮) } }4.6 带图标按钮kotlinComposable fun IconButtonExample() { Button( onClick { }, modifier Modifier.fillMaxWidth() ) { Icon(Icons.Default.Add, contentDescription null) Spacer(modifier Modifier.width(8.dp)) Text(添加) } }4.7 按钮状态kotlinComposable fun ButtonStatesExample() { var isLoading by remember { mutableStateOf(false) } Column { Button( onClick { }, enabled false, modifier Modifier.fillMaxWidth() ) { Text(禁用按钮) } Button( onClick { isLoading !isLoading }, modifier Modifier.fillMaxWidth() ) { if (isLoading) { CircularProgressIndicator( modifier Modifier.size(24.dp), color Color.White ) } else { Text(点击加载) } } } }五、导航组件5.1 TopAppBarkotlinComposable fun TopAppBarExample() { Scaffold( topBar { TopAppBar( title { Text(标题) }, navigationIcon { IconButton(onClick { }) { Icon(Icons.Default.ArrowBack, contentDescription 返回) } }, actions { IconButton(onClick { }) { Icon(Icons.Default.Search, contentDescription 搜索) } IconButton(onClick { }) { Icon(Icons.Default.MoreVert, contentDescription 更多) } }, colors TopAppBarDefaults.topAppBarColors( containerColor MaterialTheme.colorScheme.primaryContainer, titleContentColor MaterialTheme.colorScheme.onPrimaryContainer ) ) } ) { paddingValues - Box(modifier Modifier.padding(paddingValues)) { // 内容 } } } // 中型顶部栏 Composable fun CenterAlignedTopAppBarExample() { CenterAlignedTopAppBar( title { Text(居中标题) }, navigationIcon { IconButton(onClick { }) { Icon(Icons.Default.ArrowBack, null) } }, actions { IconButton(onClick { }) { Icon(Icons.Default.Share, null) } } ) } // 大型顶部栏 Composable fun LargeTopAppBarExample() { LargeTopAppBar( title { Text(大标题) }, navigationIcon { IconButton(onClick { }) { Icon(Icons.Default.Menu, null) } } ) }5.2 BottomNavigationkotlinComposable fun BottomNavigationExample() { val items listOf( NavigationItem(首页, Icons.Default.Home), NavigationItem(搜索, Icons.Default.Search), NavigationItem(收藏, Icons.Default.Favorite), NavigationItem(个人, Icons.Default.Person) ) var selectedIndex by remember { mutableStateOf(0) } Scaffold( bottomBar { NavigationBar { items.forEachIndexed { index, item - NavigationBarItem( selected selectedIndex index, onClick { selectedIndex index }, icon { Icon(item.icon, contentDescription item.label) }, label { Text(item.label) } ) } } } ) { paddingValues - Box( modifier Modifier .fillMaxSize() .padding(paddingValues) ) { when (selectedIndex) { 0 - HomeScreen() 1 - SearchScreen() 2 - FavoritesScreen() 3 - ProfileScreen() } } } } data class NavigationItem(val label: String, val icon: ImageVector)5.3 NavigationRail适用于平板/横屏kotlinComposable fun NavigationRailExample() { val items listOf( NavigationItem(首页, Icons.Default.Home), NavigationItem(收藏, Icons.Default.Favorite), NavigationItem(个人, Icons.Default.Person) ) var selectedIndex by remember { mutableStateOf(0) } Row { NavigationRail( modifier Modifier.fillMaxHeight(), containerColor MaterialTheme.colorScheme.surfaceVariant ) { items.forEachIndexed { index, item - NavigationRailItem( selected selectedIndex index, onClick { selectedIndex index }, icon { Icon(item.icon, contentDescription item.label) }, label { Text(item.label) } ) } } Box( modifier Modifier .fillMaxSize() .weight(1f) ) { when (selectedIndex) { 0 - HomeScreen() 1 - FavoritesScreen() 2 - ProfileScreen() } } } }六、容器组件6.1 CardkotlinComposable fun CardExample() { Card( modifier Modifier .fillMaxWidth() .padding(16.dp), colors CardDefaults.cardColors( containerColor MaterialTheme.colorScheme.surfaceVariant ), elevation CardDefaults.cardElevation( defaultElevation 4.dp ) ) { Column( modifier Modifier.padding(16.dp) ) { Text(卡片标题, style MaterialTheme.typography.titleLarge) Spacer(modifier Modifier.height(8.dp)) Text(卡片内容可以包含文本、图片等元素。) } } }6.2 SurfaceSurface是 Material Design 的基础容器支持背景、形状、高程等。kotlinComposable fun SurfaceExample() { Surface( modifier Modifier .fillMaxWidth() .padding(16.dp), shape RoundedCornerShape(12.dp), color MaterialTheme.colorScheme.primaryContainer, tonalElevation 3.dp, shadowElevation 2.dp ) { Text( text Surface 容器, modifier Modifier.padding(24.dp), color MaterialTheme.colorScheme.onPrimaryContainer ) } }七、数据展示组件7.1 Badge徽章kotlinComposable fun BadgeExample() { var notifications by remember { mutableStateOf(5) } BadgedBox( badge { Badge( containerColor MaterialTheme.colorScheme.error, contentColor Color.White ) { Text(notifications.toString()) } } ) { IconButton(onClick { notifications }) { Icon(Icons.Default.Notifications, contentDescription 通知) } } }7.2 Chip芯片kotlinComposable fun ChipExample() { val chips listOf(Android, Kotlin, Compose, Material) var selectedChips by remember { mutableStateOf(setOfString()) } Row( horizontalArrangement Arrangement.spacedBy(8.dp) ) { chips.forEach { chip - FilterChip( selected selectedChips.contains(chip), onClick { selectedChips if (selectedChips.contains(chip)) { selectedChips - chip } else { selectedChips chip } }, label { Text(chip) } ) } } } // 可关闭的芯片 Composable fun AssistChipExample() { var visible by remember { mutableStateOf(true) } if (visible) { AssistChip( onClick { }, label { Text(帮助提示) }, trailingIcon { IconButton(onClick { visible false }) { Icon(Icons.Default.Close, null, modifier Modifier.size(16.dp)) } } ) } }7.3 Switch开关kotlinComposable fun SwitchExample() { var checked by remember { mutableStateOf(false) } Row( verticalAlignment Alignment.CenterVertically, horizontalArrangement Arrangement.SpaceBetween, modifier Modifier.fillMaxWidth() ) { Text(启用通知) Switch( checked checked, onCheckedChange { checked it } ) } }7.4 Slider滑块kotlinComposable fun SliderExample() { var value by remember { mutableStateOf(0.5f) } Column { Text(音量: ${(value * 100).toInt()}%) Slider( value value, onValueChange { value it }, valueRange 0f..1f, steps 4 // 中间档位数 ) } } // 范围滑块 Composable fun RangeSliderExample() { var range by remember { mutableStateOf(0.2f..0.8f) } Column { Text(价格区间: ¥${(range.start * 100).toInt()} - ¥${(range.endInclusive * 100).toInt()}) RangeSlider( value range, onValueChange { range it }, valueRange 0f..1f, steps 9 ) } }7.5 Checkbox复选框kotlinComposable fun CheckboxExample() { var checked by remember { mutableStateOf(false) } Row( verticalAlignment Alignment.CenterVertically ) { Checkbox( checked checked, onCheckedChange { checked it } ) Text(同意服务条款) } }7.6 RadioButton单选按钮kotlinComposable fun RadioButtonExample() { val options listOf(选项一, 选项二, 选项三) var selectedOption by remember { mutableStateOf(options[0]) } Column { options.forEach { option - Row( verticalAlignment Alignment.CenterVertically ) { RadioButton( selected selectedOption option, onClick { selectedOption option } ) Text(option, modifier Modifier.padding(start 8.dp)) } } } }7.7 ProgressIndicator进度指示器kotlinComposable fun ProgressIndicatorExample() { var progress by remember { mutableStateOf(0f) } val scope rememberCoroutineScope() Column { // 圆形进度指示器 CircularProgressIndicator() Spacer(modifier Modifier.height(16.dp)) // 带进度的圆形进度指示器 CircularProgressIndicator( progress progress, modifier Modifier.size(48.dp) ) Spacer(modifier Modifier.height(16.dp)) // 线性进度指示器 LinearProgressIndicator( progress progress, modifier Modifier.fillMaxWidth() ) Button( onClick { scope.launch { while (progress 1f) { delay(100) progress 0.01f } } } ) { Text(开始加载) } } }八、反馈组件8.1 SnackbarkotlinComposable fun SnackbarExample() { val scaffoldState rememberScaffoldState() val scope rememberCoroutineScope() Scaffold( scaffoldState scaffoldState, snackbarHost { SnackbarHost(it) } ) { paddingValues - Box(modifier Modifier.padding(paddingValues)) { Button( onClick { scope.launch { scaffoldState.snackbarHostState.showSnackbar( message 操作成功, actionLabel 撤销, duration SnackbarDuration.Short ) } } ) { Text(显示 Snackbar) } } } }8.2 AlertDialogkotlinComposable fun DialogExample() { var showDialog by remember { mutableStateOf(false) } Button(onClick { showDialog true }) { Text(显示对话框) } if (showDialog) { AlertDialog( onDismissRequest { showDialog false }, title { Text(确认操作) }, text { Text(确定要执行此操作吗) }, confirmButton { TextButton(onClick { showDialog false }) { Text(确定) } }, dismissButton { TextButton(onClick { showDialog false }) { Text(取消) } } ) } }九、完整实战购物应用主页kotlinComposable fun ShoppingHomeScreen() { val scaffoldState rememberScaffoldState() var selectedCategory by remember { mutableStateOf(推荐) } val categories listOf(推荐, 手机, 电脑, 家电, 服饰) Scaffold( topBar { TopAppBar( title { Text(商城) }, actions { IconButton(onClick { }) { Icon(Icons.Default.Search, null) } IconButton(onClick { }) { BadgedBox( badge { Badge { Text(3) } } ) { Icon(Icons.Default.ShoppingCart, null) } } }, colors TopAppBarDefaults.topAppBarColors( containerColor MaterialTheme.colorScheme.primary, titleContentColor Color.White ) ) }, bottomBar { NavigationBar { val items listOf( 首页 to Icons.Default.Home, 分类 to Icons.Default.Category, 购物车 to Icons.Default.ShoppingCart, 个人 to Icons.Default.Person ) var selected by remember { mutableStateOf(0) } items.forEachIndexed { index, (label, icon) - NavigationBarItem( selected selected index, onClick { selected index }, icon { Icon(icon, null) }, label { Text(label) } ) } } } ) { paddingValues - Column( modifier Modifier .fillMaxSize() .padding(paddingValues) ) { // 分类标签栏 LazyRow( contentPadding PaddingValues(horizontal 16.dp), horizontalArrangement Arrangement.spacedBy(8.dp) ) { items(categories) { category - FilterChip( selected selectedCategory category, onClick { selectedCategory category }, label { Text(category) } ) } } // 商品列表 LazyVerticalGrid( columns GridCells.Fixed(2), contentPadding PaddingValues(16.dp), horizontalArrangement Arrangement.spacedBy(12.dp), verticalArrangement Arrangement.spacedBy(12.dp) ) { items(10) { index - ProductCard( name 商品 $index, price ¥${(index 1) * 99}, onAddToCart { // 添加到购物车 } ) } } } } } Composable fun ProductCard( name: String, price: String, onAddToCart: () - Unit ) { Card( modifier Modifier.fillMaxWidth(), elevation CardDefaults.cardElevation(defaultElevation 2.dp) ) { Column( modifier Modifier.padding(12.dp) ) { Box( modifier Modifier .fillMaxWidth() .aspectRatio(1f) .background( color MaterialTheme.colorScheme.surfaceVariant, shape RoundedCornerShape(8.dp) ) ) { // 商品图片 Icon( Icons.Default.Image, null, modifier Modifier.align(Alignment.Center), tint MaterialTheme.colorScheme.onSurfaceVariant ) } Spacer(modifier Modifier.height(8.dp)) Text( text name, style MaterialTheme.typography.bodyMedium, maxLines 1, overflow TextOverflow.Ellipsis ) Text( text price, style MaterialTheme.typography.titleMedium, color MaterialTheme.colorScheme.primary ) Spacer(modifier Modifier.height(8.dp)) Button( onClick onAddToCart, modifier Modifier.fillMaxWidth(), shape MaterialTheme.shapes.small ) { Text(加入购物车) } } } }十、Material Design 3 组件速查表组件用途主要参数Button主要操作按钮onClick, enabled, colorsOutlinedButton次要操作onClick, colorsTextButton低强调操作onClickIconButton图标按钮onClickFloatingActionButton主要悬浮操作onClickTopAppBar顶部导航栏title, navigationIcon, actionsBottomNavigation底部导航items, selectedIndexNavigationRail侧边导航大屏幕items, selectedIndexCard容器卡片colors, elevationSurface基础容器color, shape, elevationBadge徽章/角标containerColorChip标签/筛选onClick, label, selectedSwitch开关控制checked, onCheckedChangeSlider滑动选择value, onValueChangeCheckbox多选checked, onCheckedChangeRadioButton单选selected, onClickCircularProgressIndicator圆形进度progressLinearProgressIndicator线性进度progressSnackbar底部提示action, durationAlertDialog对话框title, text, confirmButtonDropdownMenu下拉菜单expanded, onDismissRequest练习题题一创建一个完整的应用主题包含深色和浅色模式切换功能。题二使用Card、Button、Switch等组件实现一个设备控制面板。题三实现一个带有底部导航栏的应用包含三个页面首页、收藏、个人中心。题四使用RangeSlider实现商品价格筛选功能。题五创建一组筛选芯片Chip支持单选和多选模式。写在最后Material Design 3 是 Compose 的官方设计语言掌握 Material 3 组件库是开发现代化 Android 应用的必备技能。本系列已经发布了三十五篇教程覆盖了从环境搭建到高级组件的方方面面。希望这个系列能成为你在 Android 开发道路上的得力助手。下一篇文章见。