Compose Desktop实现一个圣诞树背景的时钟

之前有用JavaFx来写一些小组件,可以参看我之前的文档JAVAFX小工具,总感觉写起来不是那么顺手。一直在找一些替代方案,有想过使用electron来实现。偶然发现可以使用KMP(kotlin multipart platform)来实现,Compose正好也是支持桌面版的编写。

之前一直是写JAVA,Compose使用的是Kotlin来编写,在函数使用上会比较便捷。决定先写一个时钟来练一下手。

构思

效果

时钟的大体框架

步骤大体可以分为下面几部

  1. 先画一个表盘
  2. 在画一个中心点
  3. 在画时针,分针,秒针
  4. 想办法这三个针动起来
  5. 初始化对应时间,赋值这三个针上

表盘

这里采用Row进行布局,画原型表盘时,需要用到canvas来进行绘制。Compose同理也是支持的,也提供了非常便捷的操作。

ini 复制代码
Canvas(modifier = Modifier.size(200.dp, 200.dp)
            ,
            onDraw = {
                // Head
                drawCircle(
                    Brush.linearGradient(
                        colors = listOf(Color.Red, Color.Green)
                    ),
                    radius = size.width / 2,
                    center = center,
                    style = Stroke(width = 5.0f)
                )
              }
        )
                

画了一个200*200的圆

中心点

ini 复制代码
// 画一个中心圆点
drawCircle(
    color = Color.Black,
    radius = 4.0f,
    center = center
)

这个指定对应的位置在正中心即可。

时针,分针,秒针

这时,需要用到sin,cos函数来计算对应的角度,通过圆的半径(100)来计算时针,分针,秒针对应的x,y轴的坐标。

ini 复制代码
// 弧度值
val rad = Math.PI * 2 / 360 * localTime.second.toDouble() * 6
val length = (size.width / 2 - size.width * 0.075f * 0.5)

// 画秒针
drawLine(
    color = Color.Black,
    start = center,
    end = center + Offset((Math.sin(rad) * length).toFloat(), (-Math.cos(rad) * length).toFloat()),
    strokeWidth = 2.0f
)
ini 复制代码
// 弧度值
val rad = Math.PI * 2 / 360 * (localTime.minute.toDouble() + localTime.second.toDouble() / 60) * 6
val length = size.width / 2 * 0.75f
// 画分针
drawLine(
    color = Color.Black,
    start = center,
    end = center + Offset((Math.sin(rad) * length).toFloat(), (-Math.cos(rad) * length).toFloat()),
    strokeWidth = 2.0f,
)
ini 复制代码
// 弧度值
val rad = Math.PI * 2 / 360 * (localTime.hour.toDouble() + localTime.minute.toDouble() / 60 + localTime.second.toDouble() / 3600) * 30
val length = size.width / 2 * 0.5f
// 画时针
drawLine(
    color = Color.Black,
    start = center,
    end = center + Offset((Math.sin(rad) * length).toFloat(), (-Math.cos(rad) * length).toFloat()),
    strokeWidth = 3.0f,
)

计算分针时,需要叠加上秒针;计算时针角度时,需要叠加上分针和秒针。

画1~12点的刻度

这个地方有一个难点,Compose的canvas是不支持直接画文字的,这个时候就需要调用底层画布来进行绘制。同理也需要计算每个点对应的x,y轴坐标。

ini 复制代码
// 画数字
for (i in 1..12) {
    drawIntoCanvas {
        // 弧度值
        val rad = Math.PI * 2 / 12 * i
        val length = size.width / 2 * 0.9f

        it.nativeCanvas.drawString(
            s = i.toString(),
            x = center.x - 2 + (Math.sin(rad) * length).toFloat(),
            y = center.y + 2 + (-Math.cos(rad) * length).toFloat(),
            paint = org.jetbrains.skia.Paint().apply {
                color = Color.Black.toArgb()
            },
            font = org.jetbrains.skia.Font(
                typeface = org.jetbrains.skia.Typeface.makeDefault(),
                size = 10.0f
            )
        )
    }
}

动起来

我们表动起来需要达到两个目标,分别是根据时间自动旋转和无线循环。需要用到compose中的无线循环动画。

ini 复制代码
// 秒针角度定义
// 设置初始值
val secondAngle by infiniteTransaction.animateFloat(
    initialValue = 0f,
    targetValue = 360f,
    animationSpec = infiniteRepeatable(
        animation = tween(60000, easing = LinearEasing)
    )
)

// 分针角度定义
// 设置初始值
val minuteAngle by infiniteTransaction.animateFloat(
    initialValue = 0f,
    targetValue = 360f,
    animationSpec = infiniteRepeatable(
        animation = tween(3600000, easing = LinearEasing),

    )
)

// 时针角度定义
// 设置初始值
val hourAngle by infiniteTransaction.animateFloat(
    initialValue = 0f,
    targetValue = 360f,
    animationSpec = infiniteRepeatable(
        animation = tween(3600000*12, easing = LinearEasing),

        )
)

表盘初始值

我是通过localtime得到小时,分,秒。在分别计算对应的x,y轴的坐标。旋转画布达到想要的角度即可。

锦上添花

进行的标题栏的隐藏,背景透明,正好圣诞节加入了圣诞树的背景。正好祝掘友圣诞快乐^_^

Compose使用体验

使用上感觉非常流畅,由于是kotlin,代码量也极少。后续会用Compose来重构我之前写的JavaFx小工具。

相关推荐
YB13751 天前
kotlin 关键字expect/actual的作用
kotlin
Android打工仔1 天前
不要再把 Flow 当作一个容器
android·kotlin
天空之城--2 天前
Android行业一周动态:编码趋势与行业资讯汇总
android·性能优化·架构·kotlin·android jetpack
JMchen2 天前
第 2 篇|Kotlin 进阶 —— 集合、循环与条件表达式
android·kotlin
YB13752 天前
Kotlin 三类关键字
kotlin
撩得Android一次心动3 天前
Jetpack Compose 知识点整理1【个人用】
android·学习·kotlin·android jetpack·compose
ForteScarlet3 天前
Kotlin 2.4.20 现已发布,新特性多不多?
android·java·开发语言·开源·kotlin·jetbrains
JMchen1233 天前
Cursor高阶玩法:.cursorrules编写与Spec-Driven开发实战,把AI调教成专属结对编程搭档
人工智能·vscode·kotlin·cursor·结对编程·spec-driven·.cursorrules
hai_android3 天前
Kotlin 协程作用域源码剖析
android·kotlin
leluckys3 天前
【KMP】-KMP 项目commonMain、androidMain、iosMain 到底放什么?
kotlin