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()
}
相关推荐
布局呆星2 小时前
Vue3+TS 笔记:Props 与 Emits 的正确打开方式
javascript·vue.js·笔记
小李子呢02112 小时前
前端八股7--- Vue 状态管理工具(vuex和pinia)
前端·javascript·vue.js
不会写DN2 小时前
从零打造一个丝滑的 Vue 3 返回顶部组件
前端·javascript·vue.js
牧杉-惊蛰2 小时前
修改表格选中时的背景色与鼠标滑过时的背景色
前端·javascript·css·vue.js·elementui·html
林恒smileZAZ7 小时前
Vue<前端页面版本检测>
前端·javascript·vue.js
我是Superman丶12 小时前
Element UI 表格某行突出悬浮效果
前端·javascript·vue.js
Cobyte16 小时前
3.响应式系统基础:从发布订阅模式的角度理解 Vue2 的数据响应式原理
前端·javascript·vue.js
军军君0116 小时前
Three.js基础功能学习十八:智能黑板实现实例五
前端·javascript·vue.js·3d·typescript·前端框架·threejs
禅思院16 小时前
前端架构演进:基于AST的常量模块自动化迁移实践
前端·vue.js·前端框架