[//]: # (title: 在应用中使用多平台资源)
<show-structure depth="2"/>
当您[为项目设置好资源](compose-multiplatform-resources-setup.md)后,构建项目以生成特殊的`Res`类,该类提供对资源的访问权限。如需重新生成`Res`类及所有资源访问器,请再次构建项目或在IDE中重新导入项目。
之后,您可以通过生成的类从代码或外部库访问配置好的多平台资源。
## 导入生成的类
要使用已准备的资源,请导入生成的类,例如:
```kotlin
import project.composeapp.generated.resources.Res
import project.composeapp.generated.resources.example_image
说明:
自定义访问器类生成
您可以通过Gradle设置自定义生成的Res
类以满足需求。
在build.gradle.kts
文件的compose.resources {}
块中,可指定影响项目生成Res
类方式的若干设置。示例配置如下:
compose.resources {
publicResClass = false
packageOfResClass = "me.sample.library.resources"
generateResClass = auto
}
publicResClass
设为true
会使生成的Res
类变为公开。默认情况下,生成类是internal的。
packageOfResClass
允许将生成的Res
类分配到特定包(便于代码访问及最终产物隔离)。默认情况下,Compose Multiplatform会为类分配{group name}.{module name}.generated.resources
包。
generateResClass
设为always
会强制项目无条件生成Res
类。当资源库仅以传递依赖形式存在时,这可能有用。默认情况下,Compose Multiplatform使用auto
值,仅在当前项目对资源库有显式implementation
或api
依赖时才生成Res
类。
资源使用
图片
您可以将drawable资源作为简单图片、栅格化图片或XML矢量图访问。SVG图片在除Android外的所有平台受支持。
要将drawable资源作为Painter
图片访问,使用painterResource()
函数:
@Composable
fun painterResource(resource: DrawableResource): Painter {...}
该函数同步工作于除web外的所有目标平台。对于web目标,首次重组时返回空Painter
,后续重组时替换为加载的图片。
要将drawable资源作为ImageBitmap
栅格化图片访问,使用imageResource()
函数:
@Composable
fun imageResource(resource: DrawableResource): ImageBitmap {...}
要将drawable资源作为ImageVector
XML矢量图访问,使用vectorResource()
函数:
@Composable
fun vectorResource(resource: DrawableResource): ImageVector {...}
示例代码:
Image(
painter = painterResource(Res.drawable.my_icon),
contentDescription = null
)
字符串
将所有字符串资源存储在composeResources/values
目录的XML文件中。每个文件的每个条目都会生成静态访问器。
简单字符串
存储简单字符串:
<resources>
<string name="app_name">我的超赞应用</string>
<string name="title">某个标题</string>
</resources>
获取字符串资源:
Text(stringResource(Res.string.app_name))
coroutineScope.launch {
val appName = getString(Res.string.app_name)
}
字符串中可使用特殊符号如\n
(换行)、 \t
(制表符)和\uXXXX
(Unicode字符),无需像Android字符串那样转义"@"或"?"。
字符串模板
当前支持基础的字符串模板参数。创建模板时使用%<数字>
格式,并用$d
或$s
后缀表示变量占位符。例如:
<string name="str_template">你好,%2$s!你有%1$d条新消息。</string>
使用示例:
Text(stringResource(Res.string.str_template, 100, "用户名"))
字符串数组
将相关字符串分组为数组:
<string-array name="str_arr">
<item>项目★</item>
<item>项目⌘</item>
<item>项目½</item>
</string-array>
获取列表:
Text(stringArrayResource(Res.array.str_arr)[0])
coroutineScope.launch {
val appName = getStringArray(Res.array.str_arr)
}
复数形式
当UI需要显示数量时,可使用复数形式支持不同数量的语法变化(如1本书vs多本书)。实现概念与Android数量字符串相同。
定义复数:
<plurals name="new_message">
<item quantity="one">%1$d条新消息</item>
<item quantity="other">%1$d条新消息</item>
</plurals>
使用示例:
Text(pluralStringResource(Res.plurals.new_message, 1, 1))
coroutineScope.launch {
val appName = getPluralString(Res.plurals.new_message, 1, 1)
}
字体
将自定义字体(*.ttf
或*.otf
)存储在composeResources/font
目录中。加载示例:
val fontAwesome = FontFamily(Font(Res.font.font_awesome))
原始文件
要加载任何原始文件为字节数组,使用Res.readBytes(path)
函数。文件可放置在composeResources/files
目录及其子目录中。
var bytes by remember { mutableStateOf(ByteArray(0)) }
LaunchedEffect(Unit) {
bytes = Res.readBytes("files/myDir/someFile.bin")
}
Text(bytes.decodeToString())
coroutineScope.launch {
val bytes = Res.readBytes("files/myDir/someFile.bin")
}
将字节数组转换为图片
若文件是位图或XML矢量图,可使用以下函数转换:
// bytes = Res.readBytes("files/example.png")
Image(bytes.decodeToImageBitmap(), null)
// bytes = Res.readBytes("files/example.xml")
Image(bytes.decodeToImageVector(LocalDensity.current), null)
非Android平台还可将SVG转为Painter
对象:
Image(bytes.decodeToSvgPainter(LocalDensity.current), null)
资源与字符串ID的生成映射
为便于访问,Compose Multiplatform还提供了资源与字符串ID的映射:
Image(painterResource(Res.allDrawableResources["compose_multiplatform"]!!), null)
从Compose Multiplatform 1.7.3开始,所有多平台资源都打包为Android资产。这使得Android Studio能为Android源集中的Compose Multiplatform可组合项生成预览。
示例展示资源HTML页面:
// androidMain/kotlin/com/example/webview/App.kt
@OptIn(ExperimentalResourceApi::class)
@Composable
@Preview
fun App() {
MaterialTheme {
val uri = Res.getUri("files/webview/index.html")
AndroidView(factory = {
WebView(it).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
}, update = {
it.loadUrl(uri)
})
}
}
Web目标的资源预加载
网络资源(如字体和图片)通过fetch
API异步加载。初始加载或网络较慢时可能导致视觉问题(如FOUT或显示占位符)。
使用浏览器特性预加载
现代浏览器中可通过<link rel="preload">
属性预加载资源。示例:
<link rel="preload" href="./composeResources/username.composeapp.generated.resources/font/FiraMono-Regular.ttf" as="fetch" type="font/ttf" crossorigin/>
Compose Multiplatform 1.8.0-beta02引入了实验性API用于预加载字体和图片资源: preloadFont()
、 preloadImageBitmap()
和preloadImageVector()
。
示例代码:
@OptIn(ExperimentalResourceApi::class)
fun main() {
configureWebResources {
resourcePathMapping { path -> "./$path" }
}
CanvasBasedWindow("Resources + K/Wasm") {
val font1 by preloadFont(Res.font.Workbench_Regular)
val font2 by preloadFont(Res.font.font_awesome, FontWeight.Normal, FontStyle.Normal)
val emojiFont = preloadFont(Res.font.NotoColorEmoji).value
// 使用预加载资源...
}
}
与其他库和资源的交互
从外部库访问多平台资源
要使用其他库处理多平台资源,可通过Res.getUri()
获取平台特定路径:
val uri = Res.getUri("files/my_video.mp4")
远程文件
资源库仅将应用内置文件视为资源。远程文件需使用专门库(如Compose ImageLoader、Kamel或Ktor客户端)加载。
使用Java资源
虽然可在Compose Multiplatform中使用Java资源,但无法享受框架提供的扩展功能(如生成访问器、多模块支持、本地化等)。建议完全迁移到多平台资源库。
下一步?
查看官方演示项目 ,了解如何在面向iOS、Android和桌面的Compose Multiplatform项目中处理资源。
23 四月 2025