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()
}
相关推荐
踩着两条虫23 分钟前
可视化 vs 终端 vs 云端:VTJ.PRO、Claude Code、Codex 三强横评
前端·vue.js·人工智能·低代码·架构
机智的张尼玛25 分钟前
我基于 Kotlin Multiplatform 实现了一套跨平台的弱网离线同步引擎
android·开源·kotlin
前端毕业班1 小时前
uni-app 小程序支持 teleport 了
前端·javascript·vue.js
妙码生花3 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(二十一):网络请求封装优化
前端·javascript·vue.js
我是唐青枫5 小时前
Kotlin 运算符重载详解:为什么 a += b 有时改对象,有时换对象?
开发语言·kotlin
帅次6 小时前
Android 高级工程师面试:Kotlin 语法基础 近1年高频追问 22 题
android·面试·kotlin·扩展函数·空安全
sowhat887 小时前
Vue3+vite+Ts+pinia—第八章 生命周期
vue.js
这是个栗子7 小时前
【Vue代码分析】 import.meta.env.DEV:现代前端工程中的环境变量
前端·javascript·vue.js·环境变量
乌夷10 小时前
Vue.js 3 的设计思路
前端·javascript·vue.js
plainGeekDev11 小时前
Gradle 写法 → Kotlin DSL
android·java·kotlin