本文主要内容参考自
- Compose Multiplatform 1.6.0 -- Resources, UI Testing, iOS Accessibility, and Preview Annotation | The Kotlin Blog
- What's new in Compose Multiplatform 1.6.0 | Kotlin Multiplatform Development Documentation
由于掘金编辑器"文档解析"功能,所有代码段的格式均被更改,本人手动重新加上了语言标记,但实在懒得处理多余的 Tab 了,故代码前有多余缩进,望理解。
前言
Compose Multiplatform 是由 JetBrains 开发的声明式 UI 框架,允许开发者在不同平台之间共享 UI 实现。1.6.0 版本带来了几个强大的功能,以及与最新的 Kotlin 版本和 Google 最新的 Jetpack Compose 更新的兼容性。
Compose Multiplatform 1.6.0 版本更新内容包括:
- 更新了资源管理。(CMP 终于有自己的各种资源访问支持了!)
- 引入了 UI 测试 API。
- 添加了 iOS 辅助功能支持。
- 带来了许多其他功能和改进。
我们下面将逐一介绍
通用资源 API
Compose Multiplatform 1.6.0 中最大且最受期待的变化,是改进了在通用 Kotlin 代码中共享和访问资源的 API。该 API 现在允许您在 Compose Multiplatform 应用程序中包含和访问更多类型的资源。
译注:在以前,CMP 仅提供了非常简单的 resource() 函数用于返回 bytes,如果想访问特定 String/fonts 等等,都需要借助像 github.com/Skeptick/li... 这样的三方库
资源被组织在 commonMain
源集的一些目录中:
composeResources/drawable
包含图片composeResources/font
包含字体composeResources/values
包含字符串(以strings.xml
格式)composeResources/files
包含任何其他文件。
Compose Multiplatform 为所有这些资源类型(除 files
目录外)生成了类型安全的访问器。例如,在 composeResources/drawable
目录中放置一个矢量图像 compose-multiplatform.xml
后,您可以使用生成的 Res
对象在 Compose Multiplatform 代码中访问它:
kotlin
import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import kotlinproject.composeapp.generated.resources.*
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
@OptIn(ExperimentalResourceApi::class)
@Composable
fun Logo() {
Image(
painterResource(Res.drawable.compose_multiplatform),
contentDescription = "CMP Logo"
)
}
新的资源 API 还允许您为不同用例提供同一资源的变体,包括区域设置、屏幕密度或主题。无论您是本地化文本、在深色模式下更改图标颜色,还是根据屏幕分辨率提供替代图像,您都可以通过向目录名称添加限定符来表达这些约束。
要更详细地了解资源限定符以及 Compose Multiplatform 1.6.0 中新资源 API 的全面概述,请查看官方文档! 请继续往下读
以下内容又来自:Images and resources | Kotlin Multiplatform Development Documentation
资源管理
Compose Multiplatform 提供了一个特殊的库和 Gradle 插件支持,用于在所有支持的平台上的通用代码中访问资源。资源是静态内容,例如图像、字体和字符串。
该库是实验性的,其 API 可能会在将来更改。
在使用 Compose Multiplatform 中的资源时,请考虑当前情况:
-
几乎所有资源都是在调用线程中同步读取的。唯一的例外是 raw 文件和所有在 JS 平台上异步读取的资源。
-
尚不支持以流的形式读取大型 raw 文件,如长视频。请在用户设备上使用单独的文件,并使用文件系统 API 读取它们,例如 kotlinx-io 库。
-
尚不支持多模块项目。JetBrains 团队正在努力在未来的版本中添加此功能。目前,请将所有资源存储在主 application 模块中。
-
尚不支持带有资源的 Compose Multiplatform 库的发布。JetBrains 团队正在努力在未来的版本中添加此功能。
-
目前,仅为
commonMain
源集生成访问器。JetBrains 团队正在努力在未来的版本中扩展此功能。不过,您仍然可以将特定于平台的资源存储在对应平台的
composeResources
目录中,并将它们读取为字节数组。所有资源都将包含在每个最终应用程序中。
设置
要在多平台项目中访问资源,请执行以下步骤:
-
在
composeApp
目录中的build.gradle.kts
文件中,向commonMain
源集添加依赖项:kotlinkotlin { sourceSets { commonMain.dependencies { // 这是由 Compose Plugin 提供的属性,不需要自己在 toml 写 implementation(compose.components.resources) } } }
-
在
commonMain
目录中创建一个名为composeResources
的新目录: -
根据以下规则组织
composeResources
目录结构:- 图像应位于
drawable
目录中。 - 字体应位于
font
目录中。 - 字符串(
strings.xml
)应位于values
目录中。 - 其他任何层次结构的文件应位于
files
目录中。
- 图像应位于
限定符
有时,相同的资源应根据环境以不同方式呈现,例如区域设置、屏幕密度或主题。例如,您可能需要为不同语言本地化文本或调整图像以适应深色主题。为此,该库提供了特殊的限定符。
所有资源类型(除了 files
目录中的原始文件)都支持限定符。使用连字符将限定符应用于目录名称:
该库支持(按优先级顺序)以下限定符:语言、主题 和 屏幕像素密度。
- 可以同时应用不同类型的限定符。例如,"drawable-en-rUS-mdpi-dark" 是英语(语言)在美国(地区)的图像,适用于深色主题的 160 DPI 屏幕。
- 如果不存在具有请求限定符的资源,则使用默认资源(没有限定符)。
语言和区域限定符
语言由两个字母的 ISO 639-1 语言代码定义。
您可以在语言代码中添加两个字母的 ISO 3166-1-alpha-2 区域代码。在这种情况下,区域代码必须具有小写 r
前缀。
语言和区域代码不区分大小写。
主题限定符
您可以添加"light"或"dark"限定符。然后,Compose Multiplatform 根据当前系统主题选择必要的资源。
密度限定符
您可以使用以下密度限定符:
- "ldpi" − 120 DPI,0.75x 密度
- "mdpi" − 160 DPI,1x 密度
- "hdpi" − 240 DPI,1.5x 密度
- "xhdpi" − 320 DPI,2x 密度
- "xxhdpi" − 480 DPI,3x 密度
- "xxxhdpi" − 640dpi,4x 密度
资源根据系统中定义的屏幕密度进行选择。
资源使用
导入项目后,将生成一个特殊的 Res
类,用于访问资源。要手动生成 Res
类,请运行 generateComposeResClass
Gradle 任务。
图像
您可以将可绘制资源作为简单图像、光栅化图像或 XML 矢量访问:
- 要将可绘制资源作为
Painter
图像访问,请使用painterResource()
函数:
kotlin
@Composable
fun painterResource(resource: DrawableResource): Painter {...}
-
painterResource()
函数接受资源路径并返回Painter
值。该函数在除 Web 以外的所有目标上都以同步方式 工作。对于 Web 目标,它在第一次重组时返回一个空的Painter
,在后续重组中用加载的图像替换它。painterResource()
加载光栅化图像格式(例如.png
、.jpg
、.bmp
、.webp
)的BitmapPainter
或 Android XML vector drawable 的VectorPainter
。
- XML vector drawables 与 Android 具有相同的格式,但不支持对 Android 资源的外部引用。
- 要将可绘制资源作为
ImageBitmap
光栅图像访问,请使用imageResource()
函数:
kotlin
@Composable
fun imageResource(resource: DrawableResource): ImageBitmap {...}
- 要将可绘制资源作为
ImageVector
XML 矢量访问,请使用vectorResource()
函数:
kotlin
@Composable
fun vectorResource(resource: DrawableResource): ImageVector {...}
下面是您可以在 Compose Multiplatform 代码中访问图像的示例:
kotlin
Image(
painter = painterResource(Res.drawable.my_icon),
contentDescription = null
)
译者吐槽:原先的 painterResource(resource: String) 没得了,淦!
字符串
将所有字符串资源存储在 composeResources/values
目录中的 strings.xml
文件中,例如:
xml
<resources>
<string name="app_name">译站</string>
<string name="title">一些标题</string>
</resources>
strings.xml
文件中的每个项目都会生成静态访问器。
译注:
譬如,对于以下的 xml
xml<?xml version="1.0" encoding="utf-8"?> <resources> <string name="clear_content">清空</string> <string name="app_name">译站</string> <string name="tip_with_placeholder">请选择 %s 并 %s</string> </resources>
它会生成
kotlin@ExperimentalResourceApi private object String0 { public val app_name: StringResource = org.jetbrains.compose.resources.StringResource( "string:app_name", "app_name", setOf( org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"), ) ) public val clear_content: StringResource = org.jetbrains.compose.resources.StringResource( "string:clear_content", "clear_content", setOf( org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"), ) ) public val tip_with_placeholder: StringResource = org.jetbrains.compose.resources.StringResource( "string:tip_with_placeholder", "tip_with_placeholder", setOf( org.jetbrains.compose.resources.ResourceItem(setOf(), "values/strings.xml"), ) ) } @ExperimentalResourceApi internal val Res.string.app_name: StringResource get() = String0.app_name @ExperimentalResourceApi internal val Res.string.clear_content: StringResource get() = String0.clear_content @ExperimentalResourceApi internal val Res.string.tip_with_placeholder: StringResource get() = String0.tip_with_placeholder
而 Res 类长这样:
kotlin@ExperimentalResourceApi internal object Res { /** * Reads the content of the resource file at the specified path and returns it as a byte array. * * Example: `val bytes = Res.readBytes("files/key.bin")` * * @param path The path of the file to read in the compose resource's directory. * @return The content of the file as a byte array. */ public suspend fun readBytes(path: String): ByteArray = readResourceBytes(path) public object drawable public object string public object font } ```
要将字符串资源作为 String
获取,请使用以下代码:
Composable 中
kotlin
@Composable
fun stringResource(resource: StringResource): String {...}
@Composable
fun stringResource(resource: StringResource, vararg formatArgs: Any): String {...}
@Composable
fun stringArrayResource(resource: StringResource): List<String> {...}
例如:
kotlin
Text(stringResource(Res.string.app_name))
非 Composable 中
kotlin
suspend fun getString(resource: StringResource): String
suspend fun getString(resource: StringResource, vararg formatArgs: Any): String
suspend fun getStringArray(resource: StringResource): List<String>
例如:
kotlin
coroutineScope.launch {
val appName = getString(Res.string.app_name)
}
您可以在字符串资源中使用特殊符号:
\n
--- 换行\t
--- 制表符\uXXXX
--- 特定的 Unicode 字符
字符串模板
目前,字符串资源对参数具有基本支持:
xml
<!-- strings.xml -->
<resources>
<string name="str_template">你好,%1$s!您有 %2$d 条新消息。</string>
</resources>
对于用于 Composable 中的那些函数,%...s
和 %...d
之间没有区别,例如:
kotlin
Text(stringResource(Res.string.str_template, "用户名", 100))
字体
将自定义字体((*.ttf
或 *.otf
文件)存储在 composeResources/font
目录中。
要将字体加载为 Font
类型,请使用 Font()
函数:
kotlin
@Composable
fun Font(
resource: FontResource,
weight: FontWeight = FontWeight.Normal,
style: FontStyle = FontStyle.Normal
): Font
例如:
kotlin
val fontAwesome = FontFamily(Font(Res.font.font_awesome))
原始文件(Raw Files)
要将任何原始文件加载为字节数组,请使用 Res.readBytes(path)
函数:
kotlin
suspend fun readBytes(path: String): ByteArray
您可以将原始文件放在 composeResources/files
目录中,并在其中创建任何层次结构。
例如,要访问原始文件,请使用以下代码:
Composable 中
kotlin
var bytes by remember {
mutableStateOf(ByteArray(0))
}
LaunchedEffect(Unit) {
bytes = Res.readFileBytes("files/myDir/someFile.bin")
}
Text(bytes.decodeToString())
非 Composable 中
kotlin
coroutineScope.launch {
val bytes = Res.readFileBytes("files/myDir/someFile.bin")
}
远程文件
只有作为应用程序一部分的文件才被视为资源。
您还可以通过 URL 从互联网加载远程文件:
通用 UI 测试 API
UI 测试可以帮助您确保应用程序的行为符合预期。在 Compose Multiplatform 1.6.0 中,我们引入了一个实验性 API,允许您编写通用的 UI 测试,用于验证应用程序在框架支持的不同平台上的用户界面行为。
例如,您可能希望确保自定义组件在显示时正确显示带有适当前缀的信息字符串:
kotlin
@Composable
fun MyInfoComposable(info: String, modifier: Modifier) {
Text(modifier = modifier, text = "[INFO] $info")
}
在最新版本的 Compose Multiplatform 中,您现在可以使用 UI 测试来验证组件在呈现时确实正确添加了前缀([info]
)。要做到这一点,您可以使用与 Android 上的 Jetpack Compose相同的 finder、assertion、actions 和 mathcers。遵循此文档完成设置后,您可以编写一个测试来确保此前缀被正确添加:
kotlin
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.runComposeUiTest
...
class InformationTest {
@OptIn(ExperimentalTestApi::class)
@Test
fun shouldPrefixWithInfoTag() = runComposeUiTest {
setContent {
MyInfoComposable("Important things!", modifier = Modifier.testTag("info"))
}
onNodeWithTag("info").assertTextContains("[INFO]", substring = true)
}
}
在任何目标平台上运行此测试都将向您显示测试结果(对于如上的错误情况,将帮助您发现并纠正拼写错误!):
iOS 辅助功能支持
Compose Multiplatform 现在为 iOS 提供支持,使残障人士可以与 Compose UI 以与原生 UI 相同的舒适度进行交互:
- 屏幕阅读器和 VoiceOver 可以访问 Compose Multiplatform UI 的内容。
- Compose Multiplatform UI 在导航和交互上,支持与原生 UI 相同的手势。
这是因为 Compose Multiplatform 的语义数据会自动映射到 Accessibility Tree 中。您还可以将此数据用于 Accessibility Services,或使用 XCTest 框架进行测试。
有关当前辅助功能支持的实现和限制的详细信息,请参阅文档页面。
Fleet 的 @Preview 注解
在 1.6.0 版本中,Compose Multiplatform 引入了常见的 @Preview
注解(之前仅适用于 Android 和 Desktop)。这个注解由 JetBrains Fleet(从 Fleet 1.31 开始支持)。将 @Preview
添加到你的 @Composable
函数中,你就能通过边栏图标打开预览:
在由 Kotlin Multiplatform 向导 生成的项目中试用吧!
目前,Fleet 仅支持对没有参数的 @Composable
函数使用 @Preview
注解。要使用这个常见的注解,请将实验性的 compose.components.uiToolingPreview
库添加到你的依赖项中(而不是用于 Desktop 和 Android 的 compose.uiTooling
)。
Popus、Dialog 和下拉菜单可显示于平台 View 之外
当将 Compose Multiplatform 与 SwiftUI 混合使用时,您可能只想让屏幕上的一些小 Widgets 使用 Compose 渲染。从版本 1.6 开始,在这些场景中创建 Dialog
、Popup
或 Dropdown
的 Composable 可以扩展超出单个 Widget 的边界,甚至可以扩展到整个屏幕!
目前,这也适用于桌面目标,尽管目前是作为一个实验性特性。
请注意,弹出窗口和对话框仍然无法绘制超出其自身边界的任何内容(例如顶层容器的阴影)。
iOS(稳定版)
在 iOS 上,默认情况下该功能是激活的。要切换回旧的行为,请将 platformLayers
参数设置为 false
:
kotlin
ComposeUIViewController(
configure = {
platformLayers = false
}
) {
// 您的 Compose 代码
}
桌面(实验性)
要在桌面上使用此功能,请设置 compose.layers.type
系统属性。支持的值:
WINDOW
,用于将Popup
和Dialog
组件创建为独立的无装饰窗口。COMPONENT
,将Popup
或Dialog
创建为同一窗口中的单独 Swing 组件。它仅在离屏渲染时有效,当compose.swing.render.on.graphics
设置为true
时(请参阅 1.5.0 Compose Multiplatform 发行说明的 增强的 Swing 互操作 部分)。请注意,离屏渲染仅适用于ComposePanel
组件,而不适用于完整的窗口应用程序。
以下是使用 COMPONENT
属性的示例代码:
kotlin
@OptIn(ExperimentalComposeUiApi::class)
fun main() = SwingUtilities.invokeLater {
System.setProperty("compose.swing.render.on.graphics", "true")
System.setProperty("compose.layers.type", "COMPONENT")
val window = JFrame()
window.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
val contentPane = JLayeredPane()
contentPane.layout = null
val composePanel = ComposePanel()
composePanel.setBounds(200, 200, 200, 200)
composePanel.setContent {
ComposeContent()
}
composePanel.windowContainer = contentPane // Use the full window for dialogs
contentPane.add(composePanel)
window.contentPane.add(contentPane)
window.setSize(800, 600)
window.isVisible = true
}
@Composable
fun ComposeContent() {
Box(Modifier.fillMaxSize().background(Color.Green)) {
Dialog(onDismissRequest = {}) {
Box(Modifier.size(100.dp).background(Color.Yellow))
}
}
}
无论父 ComposePanel
(绿色)的边界如何,Dialog
(黄色)都会完全绘制:
来自 Compose 1.6 和 Material 3 的变更
Jetpack Compose 1.6.1
将最新版本的 Jetpack Compose 合并到项目中对所有平台的性能都有积极影响。详情请参阅Android 开发者博客上的公告(或我的翻译: Jetpack Compose 1.6 上新:滚动性能提升 20%! )。
此版本的其他显着更新包括:
- 默认字体填充的更改仅在 Android 目标中生效。然而,请确保考虑到这种更改的副作用。
- 鼠标选择在 Compose Multiplatform 中的其他目标已经得到支持。从 1.6.0 开始,这也适用于 Android。
尚未移植到 Compose Multiplatform 的 Jetpack Compose 功能:
- BasicTextField2
- 支持非线性字体缩放
- MultiParagraph.fillBoundingBoxes
- 跨平台拖放。目前仅限于 Android 上。在 Desktop 端,您可以使用现有的
Modifier.onExternalDrag
API。
JetBrains 团队正在努力在未来版本的 Compose Multiplatform 中纳入这些功能。
Compose Material 3 1.2.0
发布亮点:
-
新的实验性组件
Segmented Button
,支持单选和多选。
单选
bash
![segmented button with two items selected](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/543245cf6d76408c95262c1f229fb2e4~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=783\&h=209\&s=17250\&e=png\&b=f9f9f9)
多选
-
扩展的颜色集合,提供更多的 Surface 选项,以便更容易地突出显示 UI 中的信息。
-
实施说明:
ColorScheme
对象现在是不可变的。如果您的代码当前直接修改ColorScheme
中的颜色,请确保使用 copy 方法来更改颜色。 -
现在不再有单一的 Surface 值,而是有更多的表面 Surface 选项和Surface Container,以便更灵活地管理颜色。
-
有关 Material 3 变更的更多详细信息,请参阅 Material Design 博客上的发布文章。
其他全平台变更
文本装饰线样式支持(iOS、桌面、Web)
Compose Multiplatform 现在允许使用 PlatformTextStyle
类设置文本的下划线样式。
这个类不在 common source 中可用,需要在平台特定的代码中使用。
设置点线下划线样式的示例:
kotlin
Text(
"Hello, Compose",
style = TextStyle(
textDecoration = TextDecoration.Underline,
platformStyle = PlatformTextStyle (
textDecorationLineStyle = TextDecorationLineStyle.Dotted
)
)
)
您可以使用实线、双宽实线、点线、虚线和波浪线样式。请在源代码中查看所有可用选项。
访问系统安装的字体(iOS、桌面、Web)
您现在可以从 Compose Multiplatform 应用程序中访问系统安装的字体:使用 SystemFont
类加载具有适当字体样式和字体权重的字体:
kotlin
import androidx.compose.ui.text.platform.SystemFont
FontFamily(SystemFont("Menlo", weight = 700))
FontFamily(SystemFont("Times New Roman", FontWeight.Bold))
FontFamily(SystemFont("Webdings"))
在桌面上,您可以使用 FontFamily
函数通过指定字体系列名称来加载所有可能的字体样式(参见代码示例):
kotlin
FontFamily("Menlo")
iOS
更改 Composable View 的不透明度
ComposeUIViewController
类现在有一个更多的配置选项,可以将视图的背景不透明度更改为透明。
透明背景会对性能产生负面影响,因为它会导致额外的 Blending 步骤。
kotlin
val appController = ComposeUIViewController(configure = {
this.opaque = false
}) {
App()
}
透明背景可以帮助您实现的示例:
通过双击和三击在 SelectionContainer 中选择文本
以前,Compose Multiplatform for iOS 仅允许用户在文本输入框中使用多次点击来选择文本。现在,双击和三击手势也适用于选择在 SelectionContainer
内部的 Text
组件中的文本。
与 UIViewController 的互操作
一些未实现为 UIView
的原生 API,例如 UITabBarController
或 UINavigationController
,以前无法使用现有的互操作机制嵌入到 Compose Multiplatform UI 中。
现在,Compose Multiplatform 实现了 UIKitViewController
函数,允许您在 Compose UI 中嵌入原生 iOS View Controller。
TextField 中通过长按/单击实现类似原生的光标行为
Compose Multiplatform 现在更接近于文本字段中的原生 iOS 光标行为:
- 单击文本字段后,光标位置更加精确。
- 在文本字段中长按并拖动会导致光标移动,而不是像在 Android 上那样进入选择模式。
桌面端
实验性支持:改进的互操作
过去,使用 SwingPanel
包装器实现的互操作视图始终是矩形的,并且始终在任何 Compose Multiplatform 组件的前景中置顶。这使得任何弹出元素(下拉菜单、Toast 通知)都很难使用。通过新的实现,此问题得到解决,您现在可以在以下用例中依赖 Swing:
- 裁剪。您不再受到矩形形状的限制:裁剪和阴影修饰符现在与 SwingPanel 正确工作。
kotlin
// 启用实验性混合的必要标志
System.setProperty("compose.interop.blending", "true")
SwingPanel(
modifier = Modifier.clip(RoundedCornerShape(6.dp))
//...
)
左侧是无此功能前 `JButton` 被裁剪后的表现,右侧是开启后的:
- 重叠。可以在
SwingPanel
顶部绘制任何 Compose Multiplatform 内容,并像往常一样与其进行交互。这里,"Snackbar" 在带有可点击的 OK 按钮的 Swing 面板上方:
您可在此 PR 的描述中查看已知限制和更多详细信息。
Web
Kotlin/Wasm 构件在框架的稳定版本中可用
稳定版本的 Compose Multiplatform 现在支持 Kotlin/Wasm 目标。在切换到 1.6.0 后,您不必在依赖列表中指定特定的 dev-wasm
版本的 compose-ui
库。
要构 建带有 Wasm 目标的 Compose Multiplatform 项目,您需要拥有 Kotlin 1.9.22 及更高版本。
已知问题:缺少依赖项
默认的项目配置可能会缺少几个库:
-
org.jetbrains.compose.annotation-internal:annotation
或org.jetbrains.compose.collection-internal:collection
如果某个库依赖于不与 1.6.0 兼容的 Compose Multiplatform 1.6.0-beta02,则可能会缺少这些库。要找出是哪个库,运行以下命令(将
shared
替换为您的主模块名称):bash./gradlew shared:dependencies
您可通过将该库降级为依赖于 Compose Multiplatform 1.5.12 的版本,或要求库的作者将其升级为 Compose Multiplatform 1.6.0 来解决此问题。
-
androidx.annotation:annotation:...
或androidx.collection:collection:...
Compose Multiplatform 1.6.0 依赖于仅在 Google Maven 存储库中可用的 collection 和 annotation 库。
要使此存储库对项目可用,请将以下行添加到模块的
build.gradle.kts
文件中:
kotlin
repositories {
//...
google()
}
其他更改
- Compose Multiplatform release notes on GitHub 包含了 1.6 的详尽 PR 列表
迁移
翻译完上面的内容后,我也自己开始了迁移,从 1.5.11 迁移至 1.6.0,Material 3 也迁移至 1.2.1:
-
RichTooltip
API 发生很大改变:.../TooltipSamples.kt · Gerrit Code Review (googlesource.com) -
SwipeToDismiss
被废弃,大量 API 也变更,新用法参考:.../SwipeToDismissDemo.kt · Gerrit Code Review (googlesource.com) -
原本自带的
painterResource(path: String)
不见了,自己简单实现了一个:
kotlin
@Composable
fun painterDrawableRes(name: String, suffix: String = "png"): Painter {
val res = if (name.contains('.')) name else "$name.$suffix"
return painterResource("drawable/$res")
}
@OptIn(ExperimentalResourceApi::class)
@Composable
fun painterResource(resource: String): Painter {
return BitmapPainter(imageResource(DrawableResource(resource)))
}
具体变更见:bump Compose Multiplatform to 1.6.0 · FunnySaltyFish/Transtation-KMP@d8ddb28 (github.com)