使用Compose DeskTop 实现了一个时钟,并收获些打包小经验

最近在学Compose跨平台的内容,在上一篇文章中,已经用Compose DeskTop实现了一个秒表应用,那既然能实现秒表,那么一样的我们也可以实现时钟的应用,这一篇文章中我们就来看看如何用Compose DeskTop实现一个时钟应用

开始开发

首先我们还是先找到Main.kt文件里面main函数,并在Window里面创建一个Timeclock函数作为我们时钟的入口

image.png

TimeClock函数里面,首先创建两个变量screenWscreenY,分别表示画布的宽高,并且在Canvas里面对这俩变量赋值,表示当画布的大小发生变化的时候,更新screenWscreenY的值,触发TimeClock重组

image.png

有了画布的宽高,接下来就是要找到钟表的中心点位置,一般情况下我们把画布的中心当作钟表的中心点,所以它的x,y坐标分别是

image.png

然后由于钟表是个圆,所以我们还需要一个半径,半径的大小决定了这个钟表在画布当中所占的大小,所以半径的最大值是circleXcircleY的最小值

image.png

半径减去100的原因是不希望钟表画出来太贴边,最好能够有些许间距,当然这是个人审美,因人而异,钟表的范围已确定,接下来准备画里面的刻度,刻度这里分整点刻度与非整点刻度两部分,整点刻度用十二个数字表示,分别分布在圆周上,每经过三十度一个点,所以这里我们需要两个数组,分别存储整点的文案以及整点的角度

image.png

另外还创建了一个TextMeasurer,用来绘制文案的时候使用,有了以上这些变量,我们现在可以在Canvas里面先把整点文案绘制出来了

image.png

pointXpointY分别是计算圆周上x坐标与y坐标的函数,计算出来以后分别在减去40主要是因为drawText是从topLeft开始绘制文案,如果不减去点偏移量,文案会显的比较靠下,pointXpointY函数的代码如下

image.png

现在我们看一下效果,整点的文案已经出来了

image.png

整点文案绘制完毕,然后是非整点刻度的绘制,首先是确定好非整点刻度的角度,那就是除了圆周上整点刻度角度之外的其余角度,所以我们也创建个数组来保存这些非整点刻度的角度

image.png

然后这边希望非整点刻度是一根根小的分割线,每一根分割线都指向了钟表圆心,那么需要用到的绘制函数已经知道了,就是drawLine,然后drawLine里面start与end的坐标就通过pointXpointY函数计算出来,start坐标离圆心近点,那么第一个入参就设定为半径长度减10,end坐标离圆心远一些,那么入参就定为半径加10,代码如下

image.png

现在所有刻度都绘制完毕,效果如下

image.png

看起来有点别扭是不,10点,11点,12点看起来还好,其他的感觉有点位置偏左,想了一想也是,个位数与两位数偏移量怎么可能设置的相同呢,所以我们在drawText那里增加个位数的判断,如果是个位数,那么偏移量就比两位数的小点,代码如下

image.png

现在我们再看下效果

image.png

看起来好点了,接下来就开始绘制秒针,分针和时针,在绘制之前,我们首先想一下如何绘制,要知道这不仅仅是画三根line那样简单,每一秒三根指针在钟表上的位置都有可能变化,也就是说这是一个周期性的事件,说到周期性的事件,实现方式有很多种,在传统Android里面,我们经常使用TimeTask,线程池,JobScheduler等来实现,但这些方案都要经过生成实例来实现,而我们Composable函数是要经常发生重组的,一旦发生重组就又新建个实例,那就太消耗内存了,所以在Compose里面,我更倾向于使用Flow,因为Flow的数据流需要在一个协程作用域里面进行,而LaunchedEffect函数恰好可以在Composable函数里面提供这样一个协程作用域,另外,LaunchedEffect函数只有在key值发生变化的时候才会触发协程作用域重新执行里面的代码,如果key值不变,哪怕发生重组也不用担心重新创建Flow,现在我们就来创建这个时间的数据流

image.png

先是创建了一个LocalTime的实例time,并且用remember监听它的变化,我们在LaunchedEffect函数里面创建了一个Flow,并在上游一秒一次持续发送最新时间,在下游对time进行赋值,所以我们变量time永远都表示着最新时间,然后我们创建三个变量分别将time的时分秒赋值进去

image.png

我们先绘制秒针,秒针基本每秒都会改变个位置,它经过一分钟以后走的刻度数量刚好是60个,这60个刻度所对应的角度我们创建个list保存起来

image.png

这样我们每次绘制line的时候,对应的角度在totalList数组里面的下标值就是当前second的时间,绘制秒针的代码如下

image.png

秒针绘制完毕,我们看下效果如何

0418a1.gif

分针与秒针的原理基本相同,通过变量minute就可以在totalList中获取分针绘制的角度,我们只需要在样式上稍作修改就好,绘制分针的代码如下

image.png

运行以后的效果如下

0418a2.gif

分针也绘制完毕了,并且我们看到当秒针经过刻度12的时候,分针也往后走了一格,功能也没问题,最后我们来绘制时针,时针稍微复杂一点,因为它跟秒针分针不一样,变量hour在一个小时以内都是保持不变的,但是时针的位置不能在一个小时以内都指在整点刻度上,它需要在在一小时内从当前整点刻度走到下一个整点刻度,所以它经过的角度我们需要将hour进行适当的计算来获取,计算的代码如下所示

image.png

减去12是因为LocalTime如果不做处理,直接获取的时间是24小时制的,所以需要判断如果到了下午就要减去12,下一步乘上5是将对应整点换算成刻度,然后再加上如果是非整点,那么在两个刻度之间所经过的角度,这样计算下来,我们也可以通过hourtotalList中获取时针的绘制角度,绘制的代码基本相同,样式上稍作修改

image.png

三个指针都绘制完毕,稍作优化,在圆心的地方再绘制个小圆,小圆的颜色同画布背景色一致,达到的效果就像是指针的重合部位是空心的一样,我们看下效果

0418a4.gif

两个打包小经验

查看执行文件的log

这个主要是因为刚开始接触DeskTop开发,有些东西还比较陌生,比如打出来的包如果运行失败了,如何知道是哪里出了问题?这个在Android里面非常容易,插上线在logcat中看下日志就可以了,那么桌面程序如果出错了,日志在哪里看呢?反正Intelliji里面我找了下没找到,具体log位置是在右键打包出来的程序,然后在Contents/MacOS里面有个可执行文件,双击执行一下,它的运行日志就会在弹出来的终端里面展示出来

image.png

打出来的包运行失败

这个是上一个问题衍生出来的,因为打包失败了所以我得找是啥原因啊,写客户端最终打不了包那不是白玩吗,首先看一下是什么日志

image.png

java.lang.UnsatisfiedLinkError: Can’t load library: /Applications/TimeClock.app/Contents/app/libskiko-macos-arm64.dylib

主要是这个报错,产生这个报错的文件是在Library.kt文件里面

image.png

网上查了不少,有说把compose.desktop.currentOs改成compose.desktop.macos_x64,但是这边试了下没啥用,然后看到有人说升级一下kotlin跟Compose版本,将kotlin升级到1.7.20,Compose升级到1.2.2,但由于我当前的配置比这个推荐的版本还要高所以没有在意,我的配置如下所示

image.png

结果又尝试了几次既然失败以后,我打算把版本降级到网上推荐的那个版本,配置文件改为如下所示

image.png

想着如果再不行就用家里的另一台windows试试看了,当然Compose版本降到1.3.0以下代码里是要做一些改动的,那就是要把drawText相关代码注释掉,因为这个函数是1.3.0之后推出的,最终执行了packageDmg命令后,文件真的执行成功了,效果图如下所示

0418a6.gif

我们看到虽然整点的刻度没有了,但是我们的包的确运行成功了,至于为什么高版本的kotlin跟Compose打包出来的包运行不成功,这个还得继续找找原因。

总结

这个demo算是比较简单,但好在知道了如何将一个DeskTop程序打包成可执行文件了,不然之前包打不成还真是蛮头疼的,后面继续Compose Multiplatform的学习与小demo开发

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYkQX7uo' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片