目 录CONTENT

文章目录

Compose Multiplatform实现通用的Toast提示

Stars-one
2026-05-08 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

使用三方库

现在已经有第三方库可以使用 https://github.com/brdominguez/compose-sonner

实际它也可以作为SnackBar来使用,不过我的应用情景比较少,就当初toast来使用

我们直接依赖成功后,如下面使用:

val toaster = rememberToasterState()
Toaster(state = toaster)

Button(onClick = { toaster.show("Hello world!") }) {
    Text("Show a toast")
}

由于比较常用,所以我下面封装了下:

@Composable
fun rememberToast(): ToasterState {
    val isDark = Setting.isUseDarkTheme.currentValue
    val toaster = rememberToasterState()
    Toaster(state = toaster, maxVisibleToasts = 3, darkTheme = isDark)
    return toaster
}

fun ToasterState.showShort(str:String){
    show(str, duration = ToasterDefaults.DurationShort)
}

需要使用的话,我就可以下面来使用

Box{
	val toaster = rememberToast()
	
	Button(onClick = { toaster.show("Hello world!") }) {
	    Text("Show a toast")
	}
}

其他方案

如果觉得有些没法,使用下面更为简单的taost

看到了一位掘金大佬实现的toast,复制过来了,不过相比上述三方库就有些不够自由 因为它的本质就是靠着Box,将toast组件至于顶层

import androidx.compose.animation.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.*
import kotlin.coroutines.EmptyCoroutineContext

/**
 * Toast控制器,参考项目https://github.com/GangJust/AdbHelper
 */
class ComposeToast private constructor() {
    private val toastText = mutableStateOf("")
    private val toastStatus = mutableStateOf(false)
    private var job: Job? = null

    companion object {
        private val instance = ComposeToast()

        fun show(text: String, duration: Long = 2000L, callback: () -> Unit = {}) {
            instance.toastText.value = text
            if (!instance.isShowing) {
                cancel()
                instance.job = CoroutineScope(EmptyCoroutineContext).launch {
                    instance.toastStatus.value = true
                    delay(duration)
                    instance.toastStatus.value = false
                    callback.invoke()
                }
            }
        }

        fun cancel() {
            val job = instance.job ?: return
            if (job.isActive) {
                job.cancel()
            }
        }

        fun defaultToastController(): ComposeToast = instance
    }

    val isShowing
        get() = toastStatus.value && job?.isActive ?: false

    val text
        get() = toastText.value
}

@OptIn(ExperimentalAnimationApi::class)
@Composable //Toast视图容器
fun ComposeToastContainer(
    contentAlignment: Alignment = Alignment.BottomCenter,
    content: @Composable () -> Unit,
) {
    val controller = ComposeToast.defaultToastController()

    Box {
        content()

        BoxWithConstraints(
            contentAlignment = contentAlignment,
            modifier = Modifier.fillMaxSize(),
            content = {
                AnimatedVisibility(
                    visible = controller.isShowing,
                    enter = scaleIn(),
                    exit = scaleOut(),
                    content = {
                        Card(
                            elevation = 8.dp,
                            shape = RoundedCornerShape(16.dp),
                            backgroundColor = Color.Black,
                            modifier = Modifier.padding(vertical = 32.dp),
                            content = {
                                Text(
                                    text = controller.text,
                                    style = TextStyle.Default.copy(color = Color.White),
                                    modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp),
                                )
                            }
                        )
                    }
                )
            }
        )

    }
}

使用示例:

@Composable
fun App(){
	val scope = rememberCoroutineScope()
	var showTip by remember { mutableStateOf(false) }

	MaterialTheme() {
		ComposeToastContainer  {
			//你自己的内容
			Row{
				//一个按钮测试弹出toast
				Button(onClick = {
					  ComposeToast.show("复制成功!")
				}) {
					Text("test")
				}
			}
		}
	}
}

ComposeToast.show("复制成功!")这个代码可以在任意Compose作用域里使用,也是十分的方便,不需要关心传递什么的

0

评论区