Compose Multiplatform 1.6 上新:图片、字符串、字体的资源访问!平台互操作性增强!

本文主要内容参考自

前言

Compose Multiplatform 是由 JetBrains 开发的声明式 UI 框架,允许开发者在不同平台之间共享 UI 实现。1.6.0 版本带来了几个强大的功能,以及与最新的 Kotlin 版本和 Google 最新的 Jetpack Compose 更新的兼容性。

开始使用 Compose Multiplatform

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 目录中,并将它们读取为字节数组。所有资源都将包含在每个最终应用程序中。

设置

要在多平台项目中访问资源,请执行以下步骤:

  1. composeApp 目录中的 build.gradle.kts 文件中,向 commonMain 源集添加依赖项:

    kotlin 复制代码
     kotlin {
         sourceSets {
             commonMain.dependencies {
                 // 这是由 Compose Plugin 提供的属性,不需要自己在 toml 写
                 implementation(compose.components.resources)
             }
         }
     }
  2. commonMain 目录中创建一个名为 composeResources 的新目录:

  3. 根据以下规则组织 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 开始,在这些场景中创建 DialogPopupDropdown 的 Composable 可以扩展超出单个 Widget 的边界,甚至可以扩展到整个屏幕!

目前,这也适用于桌面目标,尽管目前是作为一个实验性特性

请注意,弹出窗口和对话框仍然无法绘制超出其自身边界的任何内容(例如顶层容器的阴影)。

iOS(稳定版)

在 iOS 上,默认情况下该功能是激活的。要切换回旧的行为,请将 platformLayers 参数设置为 false

kotlin 复制代码
     ComposeUIViewController(
         configure = {
             platformLayers = false
         }
     ) {
         // 您的 Compose 代码
     }

桌面(实验性)

要在桌面上使用此功能,请设置 compose.layers.type 系统属性。支持的值:

  • WINDOW,用于将 PopupDialog 组件创建为独立的无装饰窗口。
  • COMPONENT,将 PopupDialog 创建为同一窗口中的单独 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 功能:

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,例如 UITabBarControllerUINavigationController,以前无法使用现有的互操作机制嵌入到 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:annotationorg.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 存储库中可用的 collectionannotation 库。

    要使此存储库对项目可用,请将以下行添加到模块的 build.gradle.kts 文件中:

kotlin 复制代码
         repositories {
             //...
             google()
         }

其他更改

迁移

翻译完上面的内容后,我也自己开始了迁移,从 1.5.11 迁移至 1.6.0,Material 3 也迁移至 1.2.1:

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)

相关推荐
yzpyzp1 小时前
如果后台的Long类型的数据返回是null,那么Android客户端的数据bean的kotlin的Long类型的字段接受到数据后是null空指针吗?
android·kotlin
xvch5 小时前
Kotlin 2.1.0 入门教程(二十五)类型擦除
android·kotlin
l软件定制开发工作室14 小时前
Jetpack Architecture系列教程之(一)——Jetpack介绍
android jetpack
有点感觉1 天前
Android级联选择器,下拉菜单
kotlin
zhangphil2 天前
Android Coil3缩略图、默认占位图placeholder、error加载错误显示,Kotlin(1)
android·kotlin
xvch2 天前
Kotlin 2.1.0 入门教程(二十三)泛型、泛型约束、协变、逆变、不变
android·kotlin
xvch4 天前
Kotlin 2.1.0 入门教程(二十四)泛型、泛型约束、绝对非空类型、下划线运算符
android·kotlin
zhangphil4 天前
Android Coil ImageLoader MemoryCache设置Key与复用内存缓存,Kotlin
android·kotlin
mmsx4 天前
kotlin Java 使用ArrayList.add() ,set()前面所有值被 覆盖 的问题
android·开发语言·kotlin
lavins4 天前
android studio kotlin项目build时候提示错误 Unknown Kotlin JVM target: 21
jvm·kotlin·android studio