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()
}
相关推荐
勇往直前plus1 小时前
Vue3(篇一) 核心概念——响应式模板语法与组件基础
前端·javascript·vue.js
咩咩啃树皮1 小时前
第43篇:Vue3计算属性(computed)完全精讲——缓存机制、依赖计算、业务最优解
前端·vue.js·缓存
郝亚军6 小时前
webstorm如何创建vue 3.js
javascript·vue.js·webstorm
用户83134859306989 小时前
Cesium 实现行政区内部遮罩
vue.js·webgl·cesium
卤蛋fg69 小时前
vxe-table 自定义复制粘贴逻辑:精确控制单元格数据转换
vue.js
张人玉11 小时前
基于 Vue 3 + ECharts + Express + SQLite 构建的新能源汽车销量数据分析与可视化平台——新能源汽车销量数据分析系统
数据库·vue.js·sqlite·echarts
清风programmer13 小时前
H5与小程序通信
前端·vue.js·uni-app
Cobyte14 小时前
通过 Vite 运行手写的模板编译器
前端·javascript·vue.js
张人玉15 小时前
基于 Vue 3 + ECharts + Express + SQLite 构—— LDA 模型的新闻舆论主题识别与情感分析系统
vue.js·echarts·express
无人生还15 小时前
从 Vue3 到 React · 快速上手系列第 4 篇:条件渲染与列表渲染
前端·vue.js·react.js