上一篇我们聊了 Compose 中最基础的 8 个核心组件,这一篇将聚焦「布局容器、表单交互、页面结构」类高频组件 —— 从线性布局的 Row/Column,到页面骨架 Scaffold,再到表单常用的 Switch、Slider。

Card

Card是一个 Material Design 风格的卡片容器组件。它通常带有圆角、阴影和边框,用于在界面上展示一块独立的、有层次感的内容区域,比如信息卡片、列表项等。

Card(
    modifier = Modifier
        .fillMaxWidth()
        .padding(16.dp), // 修饰卡片,如大小、边距、点击事件等
    shape = RoundedCornerShape(8.dp), // 定义卡片的形状
    colors = CardDefaults.cardColors(
        containerColor = Color.White
    ), // 设置卡片的颜色(背景色、内容色等)
    elevation = CardDefaults.cardElevation(
        defaultElevation = 4.dp
    ), // 控制卡片的阴影高度,实现层次感
    border = BorderStroke(1.dp, Color.LightGray), // 为卡片添加边框
    content = {
        Text(
            text = "这是一个卡片示例"
        )
    } // 卡片内部的内容,默认为Column布局
)

Column/Row

Column是一个纵向线性布局容器,它会将其所有子组件按照垂直方向依次排列。你可以把它理解为一个垂直的 “容器”,里面的元素从上到下排成一列。

Column(
    modifier = Modifier
        .fillMaxWidth() // 
        .padding(16.dp), // modifier修饰整个 Column 布局
    verticalArrangement = Arrangement.Top, // 子组件在垂直方向上的排列方式
    horizontalAlignment = Alignment.CenterHorizontally, // 子组件在水平方向上的对齐方式
    content = {
        Text("顶部文本") // 第一个子组件
        Text("中间文本") // 第二个子组件
        Text("底部文本") // 第三个子组件
    } // Column 的内容区域
)

Row是一个横向线性布局容器,它会将其所有子组件按照水平方向依次排列。你可以把它理解为一个水平的 “容器”,里面的元素从左到右排成一行。

Row(
    modifier = Modifier
        .fillMaxWidth()
        .padding(16.dp), // 修饰整个 Row 布局
    horizontalArrangement = Arrangement.SpaceBetween, // 子组件在水平方向上的排列方式
    verticalAlignment = Alignment.CenterVertically, // 子组件在垂直方向上的对齐方式
    content = {
        Text("左侧文本") // 第一个子组件
        Text("中间文本") // 第二个子组件
        Text("右侧文本") // 第三个子组件
    } // Row 的内容区域
)

Box

Box是一个单一容器布局,它主要用于容纳一个或多个子组件。与 RowColumn 不同,Box 没有固定的排列方向,其子组件默认会堆叠在一起。你可以通过对齐方式来精确控制子组件在 Box 内的位置。

Box 类似于 Android 传统 View 体系中的 FrameLayout,非常适合实现组件的叠加效果,例如在一张图片上叠加文字或图标。

Box(
    modifier = Modifier
        .size(200.dp)
        .background(Color.LightGray)
        .padding(16.dp), // 修饰整个 Box 布局
    contentAlignment = Alignment.Center, // 定义所有子组件在 Box 内的对齐方式
    propagateMinConstraints = false, // 是否将 Box 的最小约束传递给子组件
    content = {
        // 第一个子组件(底层)
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_foreground),
            contentDescription = "背景图片",
            modifier = Modifier.matchParentSize() // 让图片大小与 Box 一致
        )
        // 第二个子组件(上层,会叠加在图片上)
        Text(
            text = "叠加的文本",
            color = Color.White,
            style = MaterialTheme.typography.titleLarge
        )
    } // Box 的内容区域
)

Scaffold

Scaffold是一个页面级别的布局容器,它为 Material Design 风格的应用提供了一个标准的页面结构框架。它预先定义了放置顶部导航栏(TopAppBar)、底部导航栏(BottomAppBar)、悬浮按钮(FloatingActionButton)和内容区域的位置,能够快速搭建出符合设计规范的页面。

Scaffold(
    modifier = Modifier.fillMaxSize(),
    topBar = {
        TopAppBar(
            title = { Text("我的页面") }, // 标题
            navigationIcon = { IconButton(onClick = { /* 打开抽屉/返回 */ }) { Icon(Icons.Default.Menu, contentDescription = "菜单") } }, // 左侧图标
            actions = { IconButton(onClick = { /* 搜索 */ }) { Icon(Icons.Default.Search, contentDescription = "搜索") } } // 右侧图标
        )
    }, // 顶部导航栏
    bottomBar = {
        BottomAppBar {
            IconButton(onClick = { /* 首页 */ }) { Icon(Icons.Default.Home, contentDescription = "首页") }
            IconButton(onClick = { /* 我的 */ }) { Icon(Icons.Default.Person, contentDescription = "我的") }
        }
    }, // 底部导航栏
    floatingActionButton = {
        FloatingActionButton(onClick = { /* 执行主要操作,如添加 */ }) {
            Icon(Icons.Default.Add, contentDescription = "添加")
        }
    }, // 悬浮按钮
    floatingActionButtonPosition = FabPosition.End, // 悬浮按钮的位置
    containerColor = MaterialTheme.colorScheme.background, // 内容区域的背景颜色
    // 注意:content  lambda 接收一个 PaddingValues 参数,它代表了内边距,用于防止内容被 topBar 或 bottomBar 遮挡
    content = { innerPadding ->
        LazyColumn(
            modifier = Modifier.padding(innerPadding), // 应用内边距
            contentPadding = PaddingValues(16.dp)
        ) {
            items(20) { index ->
                Text(text = "列表项 $index", modifier = Modifier.padding(vertical = 8.dp))
            }
        }
    } // 页面的主要内容区域
)

Switch

Switch是一个双态切换组件,用于在 “开启” 和 “关闭” 状态之间进行切换。它是表单中常见的交互元素,通常用于控制某个功能的启用或禁用,例如 “接收通知”、“夜间模式” 等。

同时还是是一个有状态组件,这意味着它需要你提供一个 checked 状态来控制其当前表现,并通过 onCheckedChange 回调来更新这个状态。

//    by 是一个委托属性,让我们可以像使用普通变量一样读写状态
var isSwitchChecked by remember { mutableStateOf(false) }
Switch(
    checked = isSwitchChecked, // 控制 Switch 当前是“开启”还是“关闭”
    onCheckedChange = { isSwitchChecked = it }, // 当用户点击 Switch 时触发的回调
    modifier = Modifier.padding(16.dp),
    thumbContent = if (isSwitchChecked) {
        {
            Icon(
                imageVector = Icons.Filled.Check,
                contentDescription = null,
                modifier = Modifier.size(SwitchDefaults.IconSize)
            )
        }
    } else {
        null // 未选中时不显示内容
    }, // 自定义 Switch 滑块内的内容
    enabled = true, // 控制 Switch 是否可用
    colors = SwitchDefaults.colors(
        checkedThumbColor = Color.White,         // 选中时滑块颜色
        checkedTrackColor = Color(0xFF6200EE),   // 选中时轨道颜色
        checkedIconColor = Color(0xFF6200EE),    // 选中时图标颜色(如果有 thumbContent)
        uncheckedThumbColor = Color.Gray,        // 未选中时滑块颜色
        uncheckedTrackColor = Color.LightGray,   // 未选中时轨道颜色
        disabledCheckedThumbColor = Color.DarkGray, // 禁用且选中时滑块颜色
        // ... 其他颜色属性
    ) // 自定义 Switch 的颜色
)

Slider

Slider是一个滑动选择器组件,用于让用户从一个连续的数值范围内选择一个值。常见的应用场景包括调节音量、亮度、进度条,或者设置价格、评分等。

在 Compose Material3 中,Slider 的状态管理通过 SliderState 来实现,这使得状态控制更加集中和灵活。

val sliderState = rememberSliderState(
    initialValue = 30f, // 初始值
    valueRange = 0f..100f, // 数值范围
    steps = SliderDefaults.steps(
        step = 10f, // 步长,每次滑动增加或减少 10
    )
) // 创建和管理 Slider 的状态
Slider(
    state = sliderState, // 控制 Slider 的所有状态
    modifier = Modifier
        .fillMaxWidth()
        .padding(16.dp),
    enabled = true, // 控制 Slider 是否可用
    colors = SliderDefaults.colors(
        activeTrackColor = Color(0xFF6200EE), // 已选中部分轨道颜色
        inactiveTrackColor = Color.LightGray, // 未选中部分轨道颜色
        thumbColor = Color(0xFF6200EE), // 滑块颜色
        activeTickColor = Color.White, // 选中的刻度颜色(当有 steps 时)
    ), // 自定义 Slider 的颜色
    interactionSource = remember { MutableInteractionSource() }, // 用于观察和自定义组件的交互状态(如按压、聚焦)
    thumb = {
        SliderDefaults.Thumb(
            interactionSource = interactionSource,
            colors = SliderDefaults.colors(thumbColor = Color(0xFF6200EE)),
            enabled = enabled
        )
    }, // 自定义滑块的外观
    track = { sliderState ->
        SliderDefaults.Track(
            colors = SliderDefaults.colors(
                activeTrackColor = Color(0xFF6200EE),
                inactiveTrackColor = Color.LightGray
            ),
            enabled = enabled,
            sliderState = sliderState
        )
    } // 自定义轨道的外观
)
Text(text = "当前值: ${sliderState.value.toInt()}")

TabRow&Tab

TabRow 是一个标签栏容器组件,用于承载多个 Tab 组件,形成一个可切换的标签导航栏。它负责管理标签的布局、选中状态的视觉反馈(如指示器、颜色变化),以及底部的分割线样式。通常位于页面顶部,与 Tab 组件配合使用,实现内容的分页切换(如 “推荐”“热点”“视频” 等标签页)。

Tab单个标签组件,对应 TabRow 中的一个可切换选项。它负责展示标签的内容(文本、图标),并通过 selected 属性响应选中状态,onClick 事件触发标签切换。Tab 不能单独使用,必须嵌套在 TabRowtabs lambda 中。

var selectedTabIndex by remember { mutableStateOf(0) } // 状态管理:当前选中的标签索引
TabRow( 
    selectedTabIndex = selectedTabIndex, // 当前选中的标签索引
    modifier = Modifier.fillMaxWidth(),
    containerColor = Color.White, // TabRow 的背景颜色
    contentColor = Color.Blue, // 选中标签的内容颜色(文本/图标颜色)
    indicator = { tabPositions ->
        // TabRowDefaults.SecondaryIndicator:默认的次级指示器样式
        TabRowDefaults.SecondaryIndicator(
            // 指示器偏移:跟随选中的标签位置
            modifier = Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex]),
            color = Color.Blue, // 指示器颜色
            height = 3.dp // 指示器高度
        )
    }, // 选中标签的指示器(下划线)样式
    divider = {
        HorizontalDivider(
            color = Color.LightGray, // 分割线颜色
            thickness = 1.dp // 分割线厚度
        )
    }, // TabRow 底部的分割线
    tabs = {
        Tab(
            selected = selectedTabIndex == 0,
            onClick = { selectedTabIndex = 0 },
            text = { Text("推荐") },
            icon = { Icon(Icons.Default.Star, contentDescription = null) }
        )
        Tab(
            selected = selectedTabIndex == 1,
            onClick = { selectedTabIndex = 1 },
            text = { Text("热点") },
            icon = { Icon(Icons.Default.Fire, contentDescription = null) }
        )
        Tab(
            selected = selectedTabIndex == 2,
            onClick = { selectedTabIndex = 2 },
            text = { Text("视频") },
            icon = { Icon(Icons.Default.VideoLibrary, contentDescription = null) }
        )
    } // TabRow 的子组件(必须是 Tab 组件集合
)

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐