compose loading 第四篇

53 阅读4分钟

compose loading 第四篇

利用曲线加球体运动径向渐变制作眼睛效果

device-2023-10-21-095451 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))
        ) {
            var start by remember {
                mutableStateOf(false)
            }
            var start1 by remember {
                mutableStateOf(false)
            }
            val value by animateFloatAsState(
                targetValue = if (start1) 1f else 0.0f, animationSpec = spring(
                    dampingRatio = Spring.DampingRatioLowBouncy,
                    stiffness = Spring.StiffnessLow
                ), finishedListener = {
                    if (it == 1f) {
                        start1 = false
                    } else if (it == 0f) {
                        start1 = true
                    }
                }
            )
            val key by animateFloatAsState(
                targetValue = if (value == 1f) 1f else 0f,
                animationSpec = keyframes {
                    durationMillis = 1000
                    0.0f at 300 with FastOutLinearInEasing
                    0.5f at 800 with FastOutSlowInEasing
                })
            Canvas(modifier = Modifier
                .size(48.dp)
                .align(Alignment.Center), onDraw = {
                var pathIn = Path()//眼白
                pathIn.moveTo(size.width, size.height / 2)
                pathIn.cubicTo(
                    size.width,
                    size.height / 2,
                    size.width / 2,
                    (size.height / 2) * (1 - value),
                    0f,
                    size.height / 2
                )
                pathIn.moveTo(size.width, size.height / 2)
                pathIn.cubicTo(
                    size.width,
                    size.height / 2,
                    size.width / 2,
                    size.height / 2 + (size.height / 2) * value,
                    0f,
                    size.height / 2
                )
                drawPath(path = pathIn, Color(0xFF001c3d))

                val center = Offset(size.width / 2 - (size.width / 4) * key, size.height / 2)
                val r = size.width / 4
                drawCircle(//眼球
                    brush = Brush.radialGradient(
                        listOf(
                            Color(0xFF592804),
                            Color(0xFFa17a74),
                        ), center = center
                    ), radius = r * value
                )
                drawCircle(
                    Color(0xFF592804), center = center, radius = 8.dp.value
                )

                val skinColor = Color(0xFF74bbfb)
                val path = Path()
                path.moveTo(0f, size.height / 2)
                path.cubicTo(
                    0f,
                    size.height / 2,
                    size.width / 2,
                    -size.height / 2,
                    size.width,
                    size.height / 2
                )
                path.moveTo(size.width, size.height / 2)
                path.cubicTo(
                    size.width,
                    size.height / 2,
                    size.width / 2,
                    (size.height / 2) * (1 - value),
                    0f,
                    size.height / 2
                )
                drawPath(path = path, skinColor)
                val pathDown = Path()
                pathDown.moveTo(0f, size.height / 2)
                pathDown.cubicTo(
                    0f,
                    size.height / 2,
                    size.width / 2,
                    size.height + size.height / 2,
                    size.width,
                    size.height / 2
                )
                pathDown.moveTo(size.width, size.height / 2)
                pathDown.cubicTo(
                    size.width,
                    size.height / 2,
                    size.width / 2,
                    size.height / 2 + (size.height / 2) * value,
                    0f,
                    size.height / 2
                )
                drawPath(path = pathDown, skinColor)
            })
            val scope = rememberCoroutineScope()
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    scope.launch {
                        start = true
                    }

                })
            } else {
                LaunchedEffect(key1 = "roll", block = {
                    scope.launch {
                        start1 = true
                    }

                })
            }
        }
    }
}

利用球体环绕制作太阳和月亮环绕

device-2023-10-21-140318 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))
        ) {
            var start by remember {
                mutableStateOf(false)
            }

            val key by animateFloatAsState(
                targetValue = if (start) 2f else 0f,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        5000,
                        easing = LinearEasing
                    ), repeatMode = RepeatMode.Restart
                )
            )
            Canvas(modifier = Modifier
                .size(48.dp)
                .align(Alignment.Center), onDraw = {
                translate(top = size.width / 2) {
                    drawArc(
                        color = Color(0xFF4169e1),
                        startAngle = 180f,
                        sweepAngle = 180f,
                        useCenter = true,
                        style = Fill
                    )
                }

                var radius = 30.dp.value
                var centerLeft = Offset(0f, size.height / 2)
                if (key > 1f) {
                    rotate(180f * (key - 1), pivot = center) {
                        drawCircle(
                            Color.White,
                            radius = radius / 2,
                            center = centerLeft,
                        )

                    }
                } else {
                    rotate(180f * key, pivot = center) {
                        drawCircle(
                            Brush.radialGradient(
                                listOf(
                                    Color(0xFFff4500),
                                    Color(0xFFff4500),
                                    Color.Transparent
                                ),
                                center = centerLeft, radius = radius
                            ),
                            radius = radius,
                            center = centerLeft,
                        )
                    }
                }


            })
            val scope = rememberCoroutineScope()
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    scope.launch {
                        start = true
                    }

                })
            }
        }
    }
}

利用曲线加旋转制作风车

device-2023-10-21-142313 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))
        ) {
            var start by remember {
                mutableStateOf(false)
            }

            val key by animateFloatAsState(
                targetValue = if (start) 1f else 0f,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        2000,
                        easing = FastOutSlowInEasing
                    ), repeatMode = RepeatMode.Restart
                )
            )
            Canvas(modifier = Modifier
                .size(48.dp)
                .align(Alignment.Center), onDraw = {//风车
                drawLine(
                    Color.Yellow,
                    start = center,
                    end = Offset(size.width / 2, size.height),
                    strokeWidth = 10.dp.value
                )
                rotate(360 * key, pivot = center) {
                    for (i in 0 until 2) {
                        rotate(90f * i, pivot = center) {
                            val path = Path()
                            path.moveTo(0f, size.height / 2)
                            path.cubicTo(
                                0f,
                                size.height / 2,
                                size.width / 4,
                                size.height / 4,
                                size.width / 2,
                                size.height / 2
                            )
                            path.quadraticBezierTo(
                                size.width * 3 / 4,
                                size.height * 3 / 4,
                                size.width,
                                size.height / 2
                            )
                            path.lineTo(0f, size.height / 2)
                            drawPath(path = path, Color.White)
                        }
                    }

                }

            })
            val scope = rememberCoroutineScope()
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    scope.launch {
                        start = true
                    }

                })
            }
        }
    }
}

利用曲线加球体误打误撞做的兔头

device-2023-10-21-154717 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))
        ) {
            var start by remember {
                mutableStateOf(false)
            }

            val keyMul by animateFloatAsState(
                targetValue = if (start) 1.5f else 0f,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        2000,
                        easing = FastOutSlowInEasing
                    ), repeatMode = RepeatMode.Restart
                )
            )
            val transY by animateFloatAsState(
                targetValue = if (keyMul >= 1f) 1f else 0f,
                spring(
                    dampingRatio = Spring.DampingRatioHighBouncy,
                    stiffness = Spring.StiffnessHigh
                )
            )
            Canvas(modifier = Modifier
                .size(48.dp)
                .align(Alignment.Center), onDraw = {
                val radius = 24.dp.value
                val key = if (keyMul >= 1f) 1f else keyMul
                scale(1 - key, pivot = Offset(size.width / 2, 0f)) {
                    drawCircle(
                        Color.White,
                        radius = radius,
                        center = Offset(size.width / 2, 0f)
                    )
                }
                translate(top = size.height * key) {
                    drawCircle(
                        Color.White,
                        radius = radius,
                        center = Offset(size.width / 2, 0f)
                    )
                }
                val path = Path()
                val space = sin(45f) * radius
                val centerY = size.height * key + radius
                val topY = transY * centerY
                path.moveTo(size.width / 2, topY)
                path.cubicTo(
                    size.width / 2,
                    0f,
                    size.width / 2 - space / 2, centerY - space * 2,
                    size.width / 2 - space,
                    centerY - space
                )
                path.lineTo(size.width / 2, centerY)
                path.lineTo(size.width / 2, topY)
                path.close()

                path.moveTo(size.width / 2, topY)
                path.cubicTo(
                    size.width / 2,
                    0f,
                    size.width / 2 + space / 2, centerY - space * 2,
                    size.width / 2 + space,
                    centerY - space
                )
                path.lineTo(size.width / 2, centerY)
                path.lineTo(size.width / 2, topY)
                drawPath(path = path, Color.White)

            })
            val scope = rememberCoroutineScope()
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    scope.launch {
                        start = true
                    }

                })
            }
        }
    }
}

模仿不到位的水滴

device-2023-10-23-091906 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))
        ) {
            var start by remember {
                mutableStateOf(false)
            }

            val key by animateFloatAsState(
                targetValue = if (start) 1f else 0f,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        2000,
                        easing = FastOutSlowInEasing
                    ), repeatMode = RepeatMode.Restart
                )
            )
            val transY by animateFloatAsState(
                targetValue = if (key >= 0.8f) 1f else 0f,
                spring(
                    dampingRatio = Spring.DampingRatioNoBouncy,
                    stiffness = Spring.StiffnessHigh
                )
            )
            Canvas(modifier = Modifier
                .size(48.dp)
                .align(Alignment.Center), onDraw = {
                val radius = 24.dp.value
                val color = Color(0xFF4169e1)
                scale(
                    1 - key,
                    pivot = Offset(size.width / 2, 0f)
                ) {
                    drawCircle(
                        color,
                        radius = radius,
                        center = Offset(size.width / 2, 0f),
                        alpha = if (key >= 0.8f) 0f else 1f
                    )
                }
                translate(top = size.height * (if (transY == 1f) 1f else key)) {
                    drawCircle(
                        color,
                        radius = radius,
                        center = Offset(size.width / 2, 0f)
                    )
                }
                if (key >= 0.2f) {
                    val path = Path()
                    val space = sin(45f) * radius
                    val centerY = (size.height + radius) * (if (transY == 1f) 1f else key)
                    val topY = size.height * transY
                    val bottomY = centerY - space
                    val topSecondY = centerY - space * 2
                    path.moveTo(size.width / 2, topY)
                    path.cubicTo(
                        size.width / 2,
                        topY,
                        size.width / 2 - space / 2, topSecondY,
                        size.width / 2 - space,
                        bottomY
                    )
                    path.lineTo(size.width / 2, bottomY)
                    path.lineTo(size.width / 2, topY)
                    path.close()

                    path.moveTo(size.width / 2, topY)
                    path.cubicTo(
                        size.width / 2,
                        topY,
                        size.width / 2 + space / 2, topSecondY,
                        size.width / 2 + space,
                        bottomY
                    )
                    path.lineTo(size.width / 2, bottomY)
                    path.lineTo(size.width / 2, topY)
                    drawPath(path = path, color)
                }


            })
            val scope = rememberCoroutineScope()
            if (!start) {
                LaunchedEffect(key1 = "roll", block = {
                    scope.launch {
                        start = true
                    }

                })
            }
        }
    }
}