compose loading 第一篇

120 阅读2分钟

compose loading 第一篇

需要了解下面几点

  1. animateFloatAsState插值
  2. tweenspringkeyframes动画配合infiniteRepeatable重复动画
  3. DialogCanvas布局组件

案例说明

利用弧度加色值集合

device-2023-10-19-094451 00_00_00-00_00_30.gif

Box(modifier = Modifier.fillMaxSize()) {
    Dialog(
        onDismissRequest = { /*TODO*/ },
        properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
    ) {
        Box(
            Modifier
                .wrapContentSize()
                .defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
                .align(
                    Alignment.Center
                )
                .background(Color(0x80000000), RoundedCornerShape(12.dp))
        ) {
            val durationMillis = 1000
            var colors = listOf(Color.Yellow, Color.Red, Color.Green, Color.White)
            var colorIndex by remember {
                mutableIntStateOf(0)
            }
            var isRoll by remember {
                mutableStateOf(false)
            }
            var ratioRoll = animateFloatAsState(
                targetValue = if (isRoll) 360f else 0f, animationSpec = infiniteRepeatable(
                    animation = tween(
                        durationMillis, easing = LinearEasing
                    ), repeatMode = RepeatMode.Restart
                )
            )
            var isSweeping by remember {
                mutableStateOf(false)
            }

            var ratio = animateFloatAsState(targetValue = if (!isSweeping) 330f else 30f, tween(
                durationMillis, easing = FastOutLinearInEasing
            ), finishedListener = {
                if (it == 30f) {
                    if (colorIndex < colors.size - 1) {
                        colorIndex++
                    } else {
                        colorIndex = 0
                    }
                }
            })
            if (ratio.value == 30f) {
                isSweeping = false
            } else if (ratio.value == 330f) {
                isSweeping = true
            }
            Canvas(modifier = Modifier
                .size(40.dp)
                .align(Alignment.Center), onDraw = {
                val strokeWidth = 14.dp.value
                drawArc(
                    color = colors[colorIndex],
                    startAngle = ratioRoll.value,
                    sweepAngle = ratio.value,
                    useCenter = false,
                    topLeft = Offset(strokeWidth.div(2), strokeWidth.div(2)),
                    style = Stroke(width = 10.dp.value, cap = StrokeCap.Round)
                )
            })
            if (!isRoll) {
                LaunchedEffect(key1 = "run", block = {
                    isRoll = true
                })
            }

        }
    }
}

线条加旋转绘制菊花

device-2023-10-19-115519 00_00_00-00_00_30.gif

Box(modifier = Modifier.fillMaxSize()) {
    Dialog(
        onDismissRequest = { /*TODO*/ },
        properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
    ) {
        Box(
            Modifier
                .wrapContentSize()
                .defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
                .align(
                    Alignment.Center
                )
                .background(Color(0x80000000), RoundedCornerShape(12.dp))
        ) {
            val strokeWidth = 14.dp.value
            val duration = 2000
            var start by remember {
                mutableStateOf(false)
            }
            var degree = animateIntAsState(
                targetValue = if (start) 360 else 0, animationSpec = infiniteRepeatable(
                    animation = tween(
                        duration, easing = LinearEasing
                    )
                )
            )

            Canvas(modifier = Modifier
                .size(40.dp)
                .align(Alignment.Center)
                .rotate(degree.value.toFloat()), onDraw = {
                var r = size.width.div(2)
                val padding = r / 2
                var rawX = r.times(cos(Math.toDegrees(45.0))) - strokeWidth.div(2)
                var rawY = rawX
                var stepPadding = padding.times(sin(Math.toDegrees(45.0)))
                for (i in 0 until 8) {
                    rotate(i * 45f, pivot = Offset(r, r)) {
                        drawLine(
                            color = Color.White,
                            start = Offset((r - rawX).toFloat(), (r - rawY).toFloat()),
                            end = Offset(
                                r + stepPadding.toFloat(), r + stepPadding.toFloat()
                            ),
                            strokeWidth = strokeWidth,
                            cap = StrokeCap.Round
                        )
                    }
                }
            })
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    start = true
                })
            }

        }
    }
}

圆环串珠转动效果

Screenshot_20231021-171904.png

Box(modifier = Modifier.fillMaxSize()) {
    Dialog(
        onDismissRequest = { /*TODO*/ },
        properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
    ) {
        Box(
            Modifier
                .wrapContentSize()
                .defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
                .align(
                    Alignment.Center
                )
                .background(Color(0x80000000), RoundedCornerShape(12.dp))
        ) {
            val strokeWidth = 14.dp.value
            val duration = 2000
            var start by remember {
                mutableStateOf(false)
            }
            var degree = animateIntAsState(
                targetValue = if (start) 360 else 0, animationSpec = infiniteRepeatable(
                    animation = tween(
                        duration, easing = LinearEasing
                    )
                )
            )

            Canvas(modifier = Modifier
                .size(40.dp)
                .align(Alignment.Center)
                .rotate(degree.value.toFloat()), onDraw = {
                var r = size.width.div(2)
                val padding = r / 2
                var rawX = r.times(cos(Math.toDegrees(45.0))) - strokeWidth.div(2)
                var rawY = rawX
                for (i in 0 until 8) {
                    rotate(i * 45f, pivot = Offset(r, r)) {
                        drawCircle(
                            color = Color.White,
                            radius = strokeWidth,
                            center = Offset((r - rawX).toFloat(), (r - rawY).toFloat())
                        )
                    }
                }
            })
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    start = true
                })
            }

        }
    }
}

螺旋串珠转动效果,旋转过程半径递增

device-2023-10-19-144638 00_00_00-00_00_30.gif

Box(modifier = Modifier.fillMaxSize()) {
    Dialog(
        onDismissRequest = { /*TODO*/ },
        properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
    ) {
        Box(
            Modifier
                .wrapContentSize()
                .defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
                .align(
                    Alignment.Center
                )
                .background(Color(0x80000000), RoundedCornerShape(12.dp))
        ) {
            val strokeWidth = 4.dp.value
            val duration = 2000
            var start by remember {
                mutableStateOf(false)
            }
            var degree = animateIntAsState(
                targetValue = if (start) 360 else 0, animationSpec = infiniteRepeatable(
                    animation = tween(
                        duration, easing = LinearEasing
                    )
                )
            )
            var dotRun by remember {
                mutableStateOf(false)
            }
            var dotNum = animateIntAsState(targetValue = if (dotRun) 24 else 1,
                animationSpec = tween(duration, easing = FastOutLinearInEasing),
                finishedListener = {
                    if (it == 1) {
                        dotRun = true
                    } else if (it == 24) {
                        dotRun = false
                    }
                })
            Canvas(modifier = Modifier
                .size(40.dp)
                .align(Alignment.Center)
                .rotate(degree.value.toFloat()), onDraw = {
                var r = size.width.div(2)
                for (i in 0 until dotNum.value) {
                    var padding = r * i / 24
                    var stepPadding = padding.times(sin(Math.toDegrees(45.0)))
                    rotate(i * 45f, pivot = Offset(r, r)) {
                        drawCircle(
                            color = Color.White,
                            radius = strokeWidth + (10 * i / 24f).toFloat(),
                            center = Offset(
                                r + stepPadding.toFloat(), r + stepPadding.toFloat()
                            ),
                            alpha = i / 24f
                        )
                    }
                }

            })
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    start = true
                    dotRun = true
                })
            }

        }
    }
}