Jetpack Compose 自定义 Snackbar 材料 3.0

7
如何在Compose中使用Material 3实现自定义的Snackbar?我想要改变Snackbar的对齐方式。另外,我希望在Snackbar的左侧或右侧显示动态图标。
2个回答

11

您可以使用SnackBar composable自定义snackbar,并且如果您需要的话可以在Box内使用SnackbarHost alignment更改对齐方式。

val snackState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()

Box(
    modifier = Modifier
        .fillMaxSize()
        .padding(20.dp)
) {

    Column(modifier = Modifier.fillMaxSize()) {
        Button(
            modifier = Modifier.fillMaxWidth(),
            onClick = {
                coroutineScope.launch {
                    snackState.showSnackbar("Custom Snackbar")
                }
            }) {
            Text("Show Snackbar")
        }
    }
    SnackbarHost(
        modifier=Modifier.align(Alignment.BottomStart),
        hostState = snackState
    ) { snackbarData: SnackbarData ->
        CustomSnackBar(
            R.drawable.baseline_swap_horiz_24,
            snackbarData.visuals.message,
            isRtl = true,
            containerColor = Color.Gray
        )
    }
}

@Composable
fun CustomSnackBar(
    @DrawableRes drawableRes: Int,
    message: String,
    isRtl: Boolean = true,
    containerColor: Color = Color.Black
) {
    Snackbar(containerColor = containerColor) {
        CompositionLocalProvider(
            LocalLayoutDirection provides
                    if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
        ) {
            Row {

                Icon(
                    painterResource(id = drawableRes),
                    contentDescription = null
                )
                Text(message)
            }
        }
    }
}

谢谢您的回答。我该如何动态设置图标以及图标对齐方式? - Reza Faraji
动态设置图标是什么意思?您可以将图标资源作为参数传递。对于图标的对齐方式,我假设您指的是从右到左,如果是这样,您可以使用 CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl ) {Your Icon here} 来实现。 - Thracian
我的意思是在任何可组合的地方,当我想要显示Snackbar时,调用如下:scaffoldState.showSnackbar(icon = R.drawable.icon, isLeft = true, backgroundColor: Color.Transparent)... - Reza Faraji
你可以像更新的答案一样进行自定义。 - Thracian

10

这个经过验证的答案没有正确回答问题,因为图标是以静态方式提供的,而不是动态的。图标没有传递给showSnackbar

您可以通过拥有自己的SnackbarVisuals来实现:

// Your custom visuals
// Default values are the same than SnackbarHostState.showSnackbar
data class SnackbarVisualsCustom(
    override val message: String,
    override val actionLabel: String? = null,
    override val withDismissAction: Boolean = false,
    override val duration: SnackbarDuration = if (actionLabel == null) SnackbarDuration.Short else SnackbarDuration.Indefinite
    // You can add custom things here (for you it's an icon)
    @DrawableRes val drawableRes: Int
) : SnackbarVisuals


// The way you decide how to display your custom visuals
SnackbarHost(hostState = snackbarHostState) {
    val customVisuals = it.visuals as SnackbarVisualsCustom
    Snackbar {
        // Here is your custom snackbar where you use your icon
    }
}

// To display the custom snackbar
snackbarHostStateScope.launch {
    snackbarHostState.showSnackbar(
        SnackbarVisualsCustom(
            message = "The message",
            drawableRes = R.drawable.your_icon_id
        )
    )
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接