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小工具。

相关推荐
人间有清欢3 小时前
十、kotlin的协程
kotlin
吾爱星辰3 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
ChinaDragonDreamer3 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
一丝晨光13 小时前
Java、PHP、ASP、JSP、Kotlin、.NET、Go
java·kotlin·go·php·.net·jsp·asp
500了1 天前
Kotlin基本知识
android·开发语言·kotlin
陈亦康2 天前
Armeria gPRC 高级特性 - 装饰器、无框架请求、阻塞处理器、Nacos集成、负载均衡、rpc异常处理、文档服务......
kotlin·grpc·armeria
奋斗的小鹰2 天前
kotlin 委托
android·开发语言·kotlin
Wency(王斯-CUEB)2 天前
【文献阅读】政府数字治理的改善是否促进了自然资源管理?基于智慧城市试点的准自然实验
android·kotlin·智慧城市
中游鱼2 天前
Visual Studio C# 编写加密火星坐标转换
kotlin·c#·visual studio
500了3 天前
kotlin协程
开发语言·python·kotlin