如何在Jetpack Compose中重写SnackbarData添加自定义参数?
解决Jetpack Compose Snackbar添加自定义参数的问题
原生showSnackbar确实只支持message、actionLabel和duration三个参数,要传递自定义枚举状态,我们可以绕过原生API的限制,通过Flow传递自定义事件的方式实现,具体步骤如下:
1. 定义枚举和自定义数据类
先创建状态枚举和包含所有所需参数的数据类:
// 定义Snackbar状态枚举 enum class SnackbarStatusEnum { SUCCESS, DANGER, WARNING, INFO } // 自定义Snackbar数据类,包含消息、状态和显示时长 data class CustomSnackbarData( val message: String, val status: SnackbarStatusEnum, val duration: SnackbarDuration = SnackbarDuration.Short )
2. 修改ViewModel,用Flow发送事件
在BaseViewModel中使用MutableSharedFlow来发送自定义Snackbar事件:
class BaseViewModel : ViewModel() { private val _snackbarEvents = MutableSharedFlow<CustomSnackbarData>() val snackbarEvents = _snackbarEvents.asSharedFlow() // 对外暴露的调用方法,用于触发Snackbar显示 fun showSnackbar(message: String, status: SnackbarStatusEnum) { viewModelScope.launch { _snackbarEvents.emit(CustomSnackbarData(message, status)) } } }
3. 重构BaseScreen,处理自定义事件
在BaseScreen中收集ViewModel的事件流,维护当前要显示的Snackbar状态,并自定义SnackbarHost来渲染带状态的Snackbar:
@Composable fun BaseScreen( viewModel: BaseViewModel?, content: @Composable () -> Unit ) { val scaffoldState = rememberScaffoldState() val coroutineScope = rememberCoroutineScope() // 保存当前要显示的Snackbar数据 val currentSnackbarData = remember { mutableStateOf<CustomSnackbarData?>(null) } // 监听ViewModel的Snackbar事件,更新状态并控制显示时长 viewModel?.let { vm -> LaunchedEffect(key1 = vm) { vm.snackbarEvents.collect { data -> currentSnackbarData.value = data // 根据时长自动隐藏Snackbar val delayMillis = when (data.duration) { SnackbarDuration.Short -> 1500L SnackbarDuration.Long -> 3000L SnackbarDuration.Indefinite -> Long.MAX_VALUE // 无限显示,需手动关闭 } if (delayMillis != Long.MAX_VALUE) { delay(delayMillis) currentSnackbarData.value = null } } } } Scaffold( scaffoldState = scaffoldState, snackbarHost = { // 根据当前状态渲染自定义Snackbar currentSnackbarData.value?.let { data -> CustomSnackbar( message = data.message, status = data.status, onDismiss = { currentSnackbarData.value = null } ) } } ) { innerPadding -> Column(modifier = Modifier.padding(innerPadding)) { content() } } } // 自定义Snackbar组件,根据状态调整样式 @Composable fun CustomSnackbar( message: String, status: SnackbarStatusEnum, onDismiss: () -> Unit ) { // 根据状态设置背景色 val backgroundColor = when (status) { SnackbarStatusEnum.SUCCESS -> Color(0xFF4CAF50) SnackbarStatusEnum.DANGER -> Color(0xFFF44336) SnackbarStatusEnum.WARNING -> Color(0xFFFFC107) SnackbarStatusEnum.INFO -> Color(0xFF2196F3) } Snackbar( modifier = Modifier.padding(16.dp), backgroundColor = backgroundColor, action = { TextButton(onClick = onDismiss) { Text("关闭", color = Color.White) } } ) { Text(message, color = Color.White) } }
4. 使用方式
在子页面或ViewModel中直接调用showSnackbar方法即可传递状态:
// 示例:ViewModel中触发Snackbar viewModel.showSnackbar("操作失败", SnackbarStatusEnum.DANGER)
这个方案完全绕过了原生showSnackbar的参数限制,通过Flow传递完整的自定义数据,同时保留了Snackbar的原生显示逻辑和位置。
内容的提问来源于stack exchange,提问作者Gustavo Faria
相关产品推荐
相关产品推荐

