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

相关推荐
唐青枫8 小时前
Kotlin let 详解:空安全、链式转换与实战示例
kotlin
alexhilton16 小时前
车载系统中的可扩展UI:从UI嵌入到系统窗口编排
android·kotlin·android jetpack
日光明媚1 天前
一步生成视频!One-Forcing:DMD + 零成本 GAN,训练 200 步超越多步 SOTA
android·开发语言·kotlin
plainGeekDev1 天前
Android运行时面试题:ART和JVM的区别都搞不清,别写精通了
jvm·面试·kotlin
Refrain_zc2 天前
Android Kotlin + MVVM:基于 LiveData 的段落列表音频播放与 AB 复读实现
kotlin
赏金术士3 天前
企业级 Jetpack Compose 项目(入门版)最佳结构
android·kotlin·compose
我是唐青枫3 天前
Kotlin Lambda 表达式详解:从基础语法到实战封装
开发语言·kotlin
Kapaseker3 天前
Kotlin 的扩展没有你看上去的那么简单
android·kotlin
黄林晴3 天前
告别 KMP 选型地狱!klibs.io 上线,全平台库一键筛选太省心
android·kotlin
吕氏春秋i3 天前
android kotlin Compose 蓝牙库推荐
android·gitee·kotlin