Jetpack Compose for Desktop 使用过程中遇到的几个大坑
最近在用 Jetpack Compose for Desktop 写一些好玩的,用的时候遇到了很多大坑,在这里总结如下:
Binary distribution 无法访问 ClassLoader Resources
我们有时候一定会希望从 jar 内部读取资源,这个时候我们一般会使用 this::class.java.getResource
。当你将你的应用打包为 Jar 时,这么做完全没有问题,但当你打包为 native 的 binary distribution 时,这些资源都将直接返回 null。目前还没有看到解决方案。
@See https://github.com/JetBrains/compose-jb/issues/2011
错误的使用二进制流方式从 ClassLoader Resources 中加载字体导致界面整体卡顿
当我们需要加载自定义字体时,我们首先看到的方式是
fun Font(
identity: String,
data: ByteArray,
weight: FontWeight = FontWeight.Normal,
style: FontStyle = FontStyle.Normal
): Font = LoadedFont(identity, data, weight, style)
然而当你试图从 ClassLoader Resources 中传入字体的二进制流时,你就会发现这会导致界面十分卡顿,这可能是因为重复加载了二进制流导致的。
解决方案是,改用 ResourceFont
fun Font(
resource: String,
weight: FontWeight = FontWeight.Normal,
style: FontStyle = FontStyle.Normal
): Font = ResourceFont(resource, weight, style)
如此一来,卡顿问题便得到了解决
Tray 过晚被创建导致 Notification 被忽略
我们有时候需要向操作系统发送一些通知,这个时候就必须用到 Tray(托盘),为其绑定一个 TrayState,然后调用这个 TrayState 的 sendNotification
函数,向操作系统发送通知。但是需要注意的是,sendNotification 有一个限制:
/**
* Send notification to tray. If [TrayState] is attached to [Tray], notification will be sent to
* the platform. If [TrayState] is not attached then notification will be lost.
*/
fun sendNotification(notification: Notification) {
notificationChannel.trySend(notification)
}
这会导致一个问题,如果你希望在窗口最小化的时候显示托盘,然后发送通知的话,考虑如下情况:
fun main() = application {
val isShowTray = remember { mutableStateOf(false) }
if (isShowTray.value) {
Tray(
icon = BitmapPainter(useResource("/icons/logo.png") { loadImageBitmap(it) }),
state = trayState,
tooltip = getLang("application.tray.tooltip.title").asString,
onAction = {
isShowTray.value = false
isMainWindowVisible.value = true
}
)
isMainWindowVisible.value = false
}
}
fun onMinimize(){
isShowTray.value = true
trayState.sendNotification(
Notification("Title", "Contet", Notification.Type.Info)
)
}
当我们调用 onMinimize
时,isShowTray
被设置为 true
,此时托盘应该被显示,然后发送通知,但是结果是,通知并未被发送。
这实际上是当我们发送 Notification 时,此时 trayState 还未被 attach 到我们的 Tray 上,导致了这个问题。
要想解决这个问题,只需延迟一定时间再发送 Notification 即可
fun onMinimize(){
isShowTray.value = true
scope.launch {
delay(500)
trayState.sendNotification(
Notification("Title", "Contet", Notification.Type.Info)
)
}
加载 SVG 图片时显示为全黑
当我们试图加载一个 SVG 图片时,会发现有部分图片显示为全黑,这是 skia 的一个已知问题,原因是其不支持 CSS Style,解决方案有两种:
1. 在导出 SVG 图片时不要将样式导出到 CSS,而是选择内联 (inline) 样式
2. 改用其他类型图片,如 PNG
@see https://github.com/JetBrains/compose-jb/issues/1217
SVG 图片宽高比被错误计算导致 SVG 图片缩放不符合预期
有些 SVG 图片被加载后会被错误的认为其宽高比为 1:1,而不是正常的宽高。为了解决这个问题,(经过了一整天的研究),我设计了一个 ContentScale,只要你直到这张 SVG 图片的宽高比,手动录入后即可令结果恢复正常。
class KnownScaleWrapperContentScale(
private val scale: Float,
private val baseContentScale: ContentScale
) : ContentScale {
override fun computeScaleFactor(srcSize: Size, dstSize: Size): ScaleFactor =
baseContentScale.computeScaleFactor(Size(srcSize.width * scale, srcSize.height), dstSize)
.let { it.copy(it.scaleX * scale, it.scaleY) }
}
这个build.gradle.kts里的配置
compose.desktop {
application {
mainClass = “org.example.antlr.MainKt”
nativeDistributions {
targetFormats(TargetFormat.Exe, TargetFormat.Msi)
packageName = “C语言程序中的值传递”
packageVersion = “1.0.0”
}
}
}
打包出来的exe名字是乱码的,有办法解决吗
怎么个乱码法