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()
}
相关推荐
徐小夕10 小时前
JitWord 4.0 万字分享:从协同工具到AI Word操作系统,聊聊3年产品创业史
前端·vue.js·后端
两只羊ovo12 小时前
Vue 3 + DeepSeek 流式输出实战:从“干等”到“打字机”体验
前端·vue.js
尤小小13 小时前
Vite-SSG 实践:Vue项目预渲染落地完整方案
前端·vue.js
万敏13 小时前
Vue3 全栈实战:第一阶段复盘(第1-8周)
vue.js·node.js·全栈
梨想橙汁13 小时前
Vue3 组合式 API 深度解析:ref/reactive 响应式,计算属性与侦听器
前端·vue.js
web打印社区14 小时前
浏览器静默打印?先别装第三个库了
前端·vue.js·chrome·electron·pdf
Rooting++14 小时前
小程序{{ }}和vue{{ }}语法的区别
前端·vue.js·小程序
志尊宝16 小时前
Vue3 零基础每日笔记(015):条件渲染 v-if 与 v-show——控制 DOM 生死还是控制显隐
前端·vue.js·笔记
Bs_MoneyMagnet17 小时前
基于springboot+vue的宠物殡葬管理平台的设计与实现 源码+文档
java·javascript·vue.js·spring boot·后端·宠物