Snackbar
Snackbar 是 COUI 中用于在屏幕底部展示简短提示信息的轻量反馈组件。它可以附带操作按钮(例如“撤销”),并支持多种显示时长。
引入
import io.github.suqi8.coui.kmp.basic.Snackbar
import io.github.suqi8.coui.kmp.basic.SnackbarHost
import io.github.suqi8.coui.kmp.basic.SnackbarHostState
import io.github.suqi8.coui.kmp.basic.SnackbarDuration
import io.github.suqi8.coui.kmp.basic.SnackbarResult基本用法
Snackbar 通常与 Scaffold 一起使用。你需要创建一个 SnackbarHostState,将其传给 SnackbarHost,再通过 showSnackbar 来显示消息:
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = {
SnackbarHost(state = snackbarHostState)
},
) { paddingValues ->
Box(
modifier = Modifier
.padding(paddingValues),
) {
TextButton(
text = "显示消息",
onClick = {
scope.launch {
snackbarHostState.showSnackbar("这是一条短提示")
}
},
)
}
}SnackbarHostState 与 showSnackbar
SnackbarHostState 负责管理 Snackbar 消息队列。
showSnackbar
suspend fun SnackbarHostState.showSnackbar(
message: String,
actionLabel: String? = null,
withDismissAction: Boolean = false,
duration: SnackbarDuration = SnackbarDuration.Short,
): SnackbarResult| 参数名 | 类型 | 说明 | 默认值 | 是否必须 |
|---|---|---|---|---|
| message | String | 要显示在 Snackbar 中的文本 | - | 是 |
| actionLabel | String? | 操作按钮的文本(可选) | null | 否 |
| withDismissAction | Boolean | 是否显示关闭图标 | false | 否 |
| duration | SnackbarDuration | Snackbar 显示的时长 | SnackbarDuration.Short | 否 |
返回值 SnackbarResult 用于区分 Snackbar 是被操作按钮触发,还是自然消失或关闭。
获取最新或最旧的 Snackbar
suspend fun SnackbarHostState.newestSnackbarData(): SnackbarData?
suspend fun SnackbarHostState.oldestSnackbarData(): SnackbarData?你可以通过返回的 SnackbarData 调用 dismiss() 或 performAction(),以手动关闭最新或最旧的 Snackbar。
SnackbarHost
SnackbarHost 负责根据给定的 SnackbarHostState 渲染屏幕上的 Snackbar。
@Composable
fun SnackbarHost(
state: SnackbarHostState,
modifier: Modifier = Modifier,
canSwipeToDismiss: Boolean = true,
content: @Composable (SnackbarData) -> Unit = { Snackbar(it) },
)| 参数名 | 类型 | 说明 | 默认值 | 是否必须 |
|---|---|---|---|---|
| state | SnackbarHostState | 管理 Snackbar 队列的状态 | - | 是 |
| modifier | Modifier | 应用于宿主容器的修饰符 | Modifier | 否 |
| canSwipeToDismiss | Boolean | 是否允许通过滑动手势关闭 Snackbar | true | 否 |
| content | @Composable (SnackbarData) -> Unit | 自定义每一条 Snackbar 的内容 | { Snackbar(it) } | 否 |
大多数情况下,可以直接使用默认的 content,即内置的 Snackbar 视觉样式。
Snackbar
Snackbar 定义了默认的消息样式。
@Composable
fun Snackbar(
data: SnackbarData,
modifier: Modifier = Modifier,
icon: (@Composable () -> Unit)? = null,
cornerRadius: Dp = SnackbarDefaults.CornerRadius,
singleLineCornerRadius: Dp = SnackbarDefaults.SingleLineCornerRadius,
colors: SnackbarColors = SnackbarDefaults.snackbarColors(),
insideMargin: PaddingValues = SnackbarDefaults.InsideMargin,
)| 参数名 | 类型 | 说明 | 默认值 | 是否必须 |
|---|---|---|---|---|
| data | SnackbarData | 包含消息与操作信息的数据 | - | 是 |
| modifier | Modifier | 应用于 Snackbar 容器的修饰符 | Modifier | 否 |
| icon | (@Composable () -> Unit)? | 可选前置图标,布局在 30.dp 容器内(通过 SnackbarHost 的 content 插槽传入) | null | 否 |
| cornerRadius | Dp | 消息为多行时的圆角半径 | SnackbarDefaults.CornerRadius | 否 |
| singleLineCornerRadius | Dp | 消息为单行时的圆角半径 | SnackbarDefaults.SingleLineCornerRadius | 否 |
| colors | SnackbarColors | Snackbar 的颜色配置 | SnackbarDefaults.snackbarColors() | 否 |
| insideMargin | PaddingValues | Snackbar 内容区域的内边距(当操作按钮位于尾部时,末端内边距收窄为 4.dp) | SnackbarDefaults.InsideMargin | 否 |
SnackbarColors 与 SnackbarDefaults
SnackbarColors 定义了 Snackbar 使用的颜色集合:
data class SnackbarColors(
val containerColor: Color,
val contentColor: Color,
val actionContentColor: Color,
val dismissActionContentColor: Color,
)可以通过 SnackbarDefaults.snackbarColors 创建颜色配置:
val colors = SnackbarDefaults.snackbarColors(
containerColor = COUITheme.colorScheme.surfaceContainerHighest,
contentColor = COUITheme.colorScheme.onSurfaceContainer,
actionContentColor = COUITheme.colorScheme.primary,
dismissActionContentColor = COUITheme.colorScheme.onSurfaceVariantActions,
)常量
SnackbarDefaults 同时提供 Snackbar 使用的默认圆角、文字样式与内边距:
| 常量名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| CornerRadius | Dp | 消息为多行时的圆角半径 | 16.dp |
| SingleLineCornerRadius | Dp | 消息为单行时的圆角半径 | 24.dp |
| InsideMargin | PaddingValues | Snackbar 内容的默认内边距 | PaddingValues(horizontal = 16.dp, vertical = 10.dp) |
| IconSize | Dp | 可选前置图标容器的尺寸 | 30.dp |
SnackbarDefaults.textStyle() 返回消息与操作按钮使用的默认文字样式(14sp、Medium 字重)。
SnackbarDuration 与 SnackbarResult
SnackbarDuration
SnackbarDuration 用于控制 Snackbar 显示的时长:
sealed interface SnackbarDuration {
data object Short : SnackbarDuration
data object Long : SnackbarDuration
data object Indefinite : SnackbarDuration
data class Custom(val durationMillis: Long) : SnackbarDuration
}| 选项 | 说明 | 显示时长 |
|---|---|---|
| Short | 短提示 | 约 4 秒 |
| Long | 较长提示 | 约 10 秒 |
| Indefinite | 一直显示,需手动关闭 | 直到手动关闭 |
| Custom | 自定义毫秒级时长 | 用户自定义 |
SnackbarResult
SnackbarResult 用于描述 Snackbar 的完成方式:
enum class SnackbarResult {
Dismissed,
ActionPerformed,
}进阶用法
带前置图标的 Snackbar
通过 SnackbarHost 的自定义 content 插槽,为内置 Snackbar 传入图标:
SnackbarHost(state = snackbarHostState) { data ->
Snackbar(
data = data,
icon = {
Icon(
imageVector = COUIIcons.Basic.Check,
contentDescription = null,
tint = COUITheme.colorScheme.primary
)
}
)
}带操作按钮的 Snackbar
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
TextButton(
text = "显示带操作的提示",
onClick = {
scope.launch {
val result = snackbarHostState.showSnackbar(
message = "这条消息包含操作按钮",
actionLabel = "撤销",
duration = SnackbarDuration.Short,
)
when (result) {
SnackbarResult.ActionPerformed -> { /* 处理撤销 */ }
SnackbarResult.Dismissed -> { /* 超时或被关闭 */ }
}
}
},
)可关闭且无限时长的 Snackbar
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
TextButton(
text = "显示无限时长提示",
onClick = {
scope.launch {
snackbarHostState.showSnackbar(
message = "无限时长提示,需要手动关闭",
withDismissAction = true,
duration = SnackbarDuration.Indefinite,
)
}
},
)
TextButton(
text = "关闭最早的一条",
onClick = {
scope.launch {
snackbarHostState.oldestSnackbarData()?.dismiss()
}
},
)
