compose结合 viewmodel 实现 loading ,在`@Composable`外控制show、dismiss

224 阅读1分钟

compose结合 viewmodel 实现 loading ,在@Composable外控制show、dismiss

Screen_recording_20231227_090150 00_00_00-00_00_30.gif

利用ViewModel封装loading

  1. SnackbarHost制作弹框
  2. SnackbarHostState()控制弹框显示隐藏动作
  3. val hostState = SnackbarHostState()定义在ViewModel中方便控制
class MessageTrans : ViewModel() {

    // Hoisted state
    val hostState = SnackbarHostState()
    @Composable
    fun snackProgressInit() {

        Box(
            Modifier
                .fillMaxSize()
                .background(
                    if (hostState.currentSnackbarData?.visuals == null) Color.Transparent else Color(
                        0x80000000
                    )
                )
        ) {
            SnackbarHost(hostState = hostState, modifier = Modifier.align(Alignment.Center)) {
                it.visuals.withDismissAction
                Card(
                    Modifier
                        .size(96.dp),
                    shape = RoundedCornerShape(8.dp),
                    colors = CardDefaults.cardColors(
                        containerColor = Color.DarkGray,
                        contentColor = Color.White
                    ),
                    elevation = CardDefaults.cardElevation(defaultElevation = 12.dp)
                ) {
                    var isStop by remember {
                        mutableStateOf(false)
                    }
                    var progress = animateFloatAsState(
                        targetValue = if (isStop) 1f else 0f,
                        animationSpec = infiniteRepeatable(
                            animation = tween(2000, easing = FastOutSlowInEasing),
                            repeatMode = RepeatMode.Restart
                        ),
                        label = "progress"
                    )
                    Box(Modifier.fillMaxSize()) {
                        CircularProgressIndicator(
                            progress = {
                                progress.value
                            }, strokeWidth = 4.dp,
                            strokeCap = StrokeCap.Round,
                            trackColor = Color.Transparent,
                            color = Color.Yellow,
                            modifier = Modifier
                                .size(50.dp)
                                .align(
                                    Alignment.Center
                                )
                                .rotate(360 * progress.value)
                                .shadow(
                                    2.dp,
                                    RoundedCornerShape(25.dp),
                                    true,
                                    Color.Yellow,
                                    Color.Yellow
                                )
                        )
                    }
                    LaunchedEffect(key1 = "progress", block = {
                        isStop = true
                    })
                }
            }
        }
    }


    fun show() {
        GlobalScope.launch {
            hostState.showSnackbar(
                message = "加载中...",
                duration = SnackbarDuration.Indefinite
            )
        }
    }

    fun dismiss() {
        GlobalScope.launch {
            hostState.currentSnackbarData?.dismiss()
        }
    }
}

要绘制的根布局初始化snackProgressInit,比如下面这种,目的作为遮罩覆盖在ui层之上

model = MessageTrans()
setContent {
    ComposePart1Theme {
        // A surface container using the 'background' color from the theme
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
            Greeting10(model)
            model.snackProgressInit()
        }
    }
}

测试调用方式可以是这样的

override fun onResume() {
    super.onResume()
    model.show()
    GlobalScope.launch {
        delay(10000)
        model.dismiss()
    }

}