kotlin:jetpack compose 生成动态可控的动画

Kotlin 复制代码
package com.game.circle

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

// 存储每个圆的信息
data class Circle(
    val radius: Dp,       // 圆大小
    val color: Color,        // 圆颜色
    val alpha: Float = 1f    // 透明度
)

@Composable
fun OverlappingCircleCountdown() {
    // 倒计时总时长
    val totalSeconds = 10
    // 存储所有已经绘制出来的圆
    val circles = remember { mutableStateListOf<Circle>() }
    // 当前倒计时秒数
    var currentSecond by remember { mutableStateOf(totalSeconds) }
    val scope = rememberCoroutineScope()

    var radiusNumber = 10
    LaunchedEffect(Unit) {
        // 每秒生成一个新圆
        repeat(totalSeconds) {
            radiusNumber += 10
            // 生成大小随机、颜色不同的圆
            val newCircle = Circle(
                radius = radiusNumber.dp,
                color = Color.Blue
            )

            circles.add(newCircle)
            currentSecond -= 1

            // 等待1秒
            delay(1000)
        }
    }

    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        // 画布:绘制所有重叠圆
        Canvas(
            modifier = Modifier.size(300.dp)
        ) {
            val center = Offset(size.width / 2, size.height / 2)

            // 绘制所有叠加的圆
            circles.forEach { circle ->
                drawCircle(
                    color = circle.color,
                    radius = circle.radius.toPx(),
                    center = center,
                    alpha = circle.alpha,
                    style = Stroke(width = 5.dp.toPx())
                )
            }
        }
    }
}

@Composable
fun OverlappingCircleCountdown2() {
    var isPaused by remember { mutableStateOf(false) }

    // 倒计时总时长
    val totalSeconds = 10
    // 存储所有已经绘制出来的圆
    val circles2 = remember { mutableStateListOf<Circle>() }
    // 当前倒计时秒数
    var currentSecond2 by remember { mutableStateOf(totalSeconds) }
    val scope2 = rememberCoroutineScope()
    val scope = rememberCoroutineScope()
    var job by remember {mutableStateOf<kotlinx.coroutines.Job?>(null)}
    var radiusNumber2 = 10
    var currentradiusNumber2 by remember { mutableStateOf(radiusNumber2) }

    fun startJob(){

        job = scope.launch {
            repeat(1000){
                delay(1000)
//                radiusNumber2 += 10
//                currentradiusNumber2 = radiusNumber2
                currentradiusNumber2 += 10
                // 生成大小随机、颜色不同的圆
                val newCircle = Circle(
                    radius = currentradiusNumber2.dp,
                    color = Color.Red
                )
                circles2.add(newCircle)
            }
        }
    }
    LaunchedEffect(Unit) {startJob()}

    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        // 画布:绘制所有重叠圆
        Canvas(
            modifier = Modifier.size(300.dp)
        ) {
            val center = Offset(size.width / 2, size.height / 2)

            // 绘制所有叠加的圆
            circles2.forEach { circle ->
                drawCircle(
                    color = circle.color,
                    radius = circle.radius.toPx(),
                    center = center,
                    alpha = circle.alpha,
                    style = Stroke(width = 5.dp.toPx())
                )
            }
        }
    }

    Column{
        Text("计数:$currentradiusNumber2")
        Button(onClick = {
            job?.cancel() //暂停取消
            job = null
        }) {
            Text("停止")
        }
        Button(onClick = {
            if (job?.isActive != true ) startJob()
        }) {
            Text("重新开始")
        }
        Button(onClick = {
            job?.cancel() //暂停取消
            job = null
            
            circles2.clear()
            currentradiusNumber2 = radiusNumber2
            if (job?.isActive != true ) startJob()
        }) {
            Text("重置")
        }
    }
}

// 在你的界面中直接调用
@Composable
fun CountdownScreen() {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        OverlappingCircleCountdown2()
    }

}

@Preview
@Composable
fun CountdownScreenPreview(){
    CountdownScreen()
}
相关推荐
xxwl5858 小时前
vue3的入门学习
前端·vue.js·学习
web打印社区8 小时前
政务办事大厅:叫号小票、办理回执网页怎么静默出纸
前端·javascript·vue.js·pdf·html·政务
斯内普吖8 小时前
(开源)水果蔬菜商城实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源
ss2739 小时前
AI全栈实战 | 2.2-02 React 思维模型:数据不可变 vs Vue 数据可变,两种哲学把复杂度推给谁
前端·vue.js·react.js
天衍四九-9 小时前
Docker Compose企业实战系列(三):Vue/React前端项目容器化完整部署
前端·vue.js·docker
墨鱼老师10 小时前
SpringBoot+Vue 毕设项目开发踩坑记录(前后端分离)
vue.js·spring boot·毕业设计·课程设计·前后端分离·java 毕设
雪芽蓝域zzs10 小时前
Vue3 + Element Plus el-select 下拉弹窗
vue.js·elementui
ZealSinger10 小时前
Kotlin后端别再用GlobalScope
kotlin·协程·后端开发·结构化并发
Wx-bishekaifayuan11 小时前
springboot房屋租赁系统11574-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·sql·spring·课程设计
小白的码BUG之路11 小时前
Docker -- 构建nginx镜像,启动vue项目
vue.js·nginx·docker