【Compose multiplatform教程20】在应用程序中使用多平台资源
为项目设置资源后,生成项目以生成提供资源访问权限的特殊类。要重新生成类和所有资源访问器,请再次生成项目或在 IDE 中重新导入项目。Res
Res
之后,您可以使用生成的类从您的代码或外部库访问配置的多平台资源。
自定义访问器类生成
您可以使用 Gradle 设置自定义生成的类以满足您的需求。Res
在文件的块中,您可以指定多个设置,这些设置会影响为项目生成类的方式。示例配置如下所示:compose.resources {}
build.gradle.kts
Res
compose.resources {
publicResClass = false
packageOfResClass = "me.sample.library.resources"
generateResClass = auto
}
publicResClass
设置为 将生成的类设为公共。默认情况下,生成的类是 internal。true
Res
packageOfResClass
允许您将生成的类分配给特定的包(以便在代码中访问,以及在最终工件中进行隔离)。默认情况下,Compose Multiplatform 会将软件包分配给类。Res
{group name}.{module name}.generated.resources
generateResClass
设置为 使项目无条件生成类。当资源库仅可传递时,这可能很有用。默认情况下,仅当当前项目对资源库具有显式或依赖项时,Compose Multiplatform 才会使用该值来生成类。always
Res
auto
Res
implementation
api
资源使用情况
图像
您可以以简单图片、栅格化图片或 XML 矢量的形式访问可绘制资源。除 Android 之外的所有平台都支持 SVG 图像。
-
如需以图片形式访问可绘制对象资源,请使用以下函数:
Painter
painterResource()
@Composable
fun painterResource(resource: DrawableResource): Painter {...}
该函数采用资源路径并返回一个值。该函数在除 Web 之外的所有目标上同步工作。对于 Web 目标,它会为第一次合成返回一个空值,该合成将在后续合成中替换为加载的图像。painterResource()
Painter
Painter
painterResource()
加载 a 用于栅格化图像格式,例如 、 、 、 或 用于 Android XML 矢量可绘制对象格式的 a。BitmapPainter
.png
.jpg
.bmp
.webp
VectorPainter
XML 矢量可绘制对象的格式与 Android 相同,只是它们不支持对 Android 资源的外部引用。
需以Bitmap图像的形式访问可绘制资源,请使用以下函数:ImageBitmap
imageResource()
@Composable
fun imageResource(resource: DrawableResource): ImageBitmap {...}
如需以 XML 矢量的形式访问可绘制资源,请使用以下函数:ImageVector
vectorResource()
@Composable
fun vectorResource(resource: DrawableResource): ImageVector {...}
以下示例说明了如何在 Compose Multiplatform 代码中访问图像:
Image(
painter = painterResource(Res.drawable.my_icon),
contentDescription = null
)
字符串
将所有字符串资源存储在目录中的 XML 文件中。将为每个文件中的每个项生成一个静态访问器。composeResources/values
简单字符串
要存储简单字符串,请在 XML 中添加一个元素:<string>
<resources>
<string name="app_name">My awesome app</string>
<string name="title">Some title</string>
</resources>
要将字符串资源作为 获取,请使用以下代码:String
From 可组合代码
@Composable
fun stringResource(resource: StringResource): String {...}
@Composable
fun stringResource(resource: StringResource, vararg formatArgs: Any): String {...}
从不可组合代码
suspend fun getString(resource: StringResource): String
suspend fun getString(resource: StringResource, vararg formatArgs: Any): String
例如:
coroutineScope.launch {
val appName = getString(Res.string.app_name)
}
您可以在字符串资源中使用特殊符号:
-
\n
— 换行 -
\t
— 对于 Tab 符号 -
\uXXXX
— 对于特定的 Unicode 字符 -
字符串模板
目前,参数在字符串资源中具有基本支持:
<resources>
<string name="str_template">Hello, %1$s! You have %2$d new messages.</string>
</resources>
使用带有可组合代码中的参数的字符串模板时,和 没有区别,例如:%...s
%...d
Text(stringResource(Res.string.str_template, "User_name", 100))
字符串数组
您可以将相关字符串分组到一个数组中,并自动将它们作为对象访问:List<String>
<resources>
<string name="app_name">My awesome app</string>
<string name="title">Some title</string>
<string-array name="str_arr">
<item>item \u2605</item>
<item>item \u2318</item>
<item>item \u00BD</item>
</string-array>
</resources>
要获取相应的List,请使用以下代码:
From 可组合代码
@Composable
fun stringArrayResource(resource: StringArrayResource): List<String> {...}
从不可组合代码
suspend fun getStringArray(resource: StringArrayResource): List<String>
例如:
coroutineScope.launch {
val appName = getStringArray(Res.array.str_arr)
}
复数
当您的 UI 显示某物的数量时,您可能希望支持同一事物的不同数量(一本书、多本书等)的语法一致性,而无需创建以编程方式无关的字符串。
Compose Multiplatform 中的概念和基本实现与 Android 上的数量字符串相同。有关在项目中使用复数的最佳实践和细微差别的更多信息,请参阅 Android 文档。
-
支持的变体包括 、 、 、 、 和 。请注意,并非所有语言都会考虑所有变体:例如,对于英语,它会被忽略,因为它与除 1 之外的任何其他复数相同。依靠语言专家来了解该语言实际上坚持的区别。
zero
one
two
few
many
other
zero
-
通常可以通过使用数量中立的公式(如 “Books: 1”)来避免数量字符串。如果这不会恶化用户体验,
要定义复数形式,请将元素添加到目录中的任何文件。集合是使用 name 属性(而不是 XML 文件的名称)引用的简单资源。因此,您可以在一个元素下的一个 XML 文件中将资源与其他简单资源组合在一起:<plurals>
.xml
composeResources/value s
plural s
plurals
<resources>
<resources>
<string name="app_name">My awesome app</string>
<string name="title">Some title</string>
<plurals name="new_message">
<item quantity="one">%1$d new message</item>
<item quantity="other">%1$d new messages</item>
</plurals>
</resources>
要将复数形式作为 a 访问,请使用以下代码:String
From 可组合代码
@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int): String {...}
@Composable
fun pluralStringResource(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): String {...}
从不可组合代码
suspend fun getPluralString(resource: PluralStringResource, quantity: Int): String
suspend fun getPluralString(resource: PluralStringResource, quantity: Int, vararg formatArgs: Any): String
例如:
coroutineScope.launch {
val appName = getPluralString(Res.plurals.new_message, 1, 1)
}
字体
自定义字体存储在目录中 or files.composeResources/font
*.ttf
*.otf
要将字体加载为类型,请使用以下函数:Font
Font()
@Composable
fun Font(
resource: FontResource,
weight: FontWeight = FontWeight.Normal,
style: FontStyle = FontStyle.Normal
): Font
例如:
val fontAwesome = FontFamily(Font(Res.font.font_awesome))
Raw 文件
要将任何原始文件加载为字节数组,请使用以下函数:Res.readBytes(path)
suspend fun readBytes(path: String): ByteArray
您可以将原始文件放在目录中,并在其中创建任何层次结构。composeResources/files
例如,要访问原始文件,请使用以下代码:
From 可组合代码
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")
}
将字节数组转换为图像
如果您正在读取的文件是位图(JPEG、PNG、BMP、WEBP)或 XML 矢量图像,则可以使用以下函数将它们转换为适合可组合项的对象。ImageBitmap
ImageVector
Image()
访问 Raw 文件部分所示的原始文件,然后将结果传递给可组合项:
// 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
// bytes = Res.readBytes("files/example.svg")
Image(bytes.decodeToSvgPainter(LocalDensity.current), null)
为资源和字符串 ID 生成的映射
为了便于访问,Compose Multiplatform 还使用字符串 ID 映射资源。您可以使用文件名作为键来访问它们:
al Res.allDrawableResources: Map<String, DrawableResource>
val Res.allStringResources: Map<String, StringResource>
val Res.allStringArrayResources: Map<String, StringArrayResource>
val Res.allPluralStringResources: Map<String, PluralStringResource>
val Res.allFontResources: Map<String, FontResource>
将映射的资源传递给可组合项的示例:
Image(painterResource(Res.allDrawableResources["compose_multiplatform"]!!), null)
将多平台资源组合为 Android 资产
从 Compose Multiplatform 1.7.3 开始,所有多平台资源都打包到 Android 资产中。这样,Android Studio 就可以在 Android 源代码集中为 Compose Multiplatform 可组合项生成预览。
Android Studio 预览仅适用于 Android 源代码集中的可组合项。它们还需要最新版本的 AGP 之一:8.5.2、8.6.0-rc01 或 8.7.0-alpha04。
使用多平台资源作为 Android 资产还可以从 Android 上的 WebView 和媒体播放器组件直接访问,因为资源可以通过简单的路径访问,例如 .Res.getUri("files/index.html")
Android 可组合项显示带有资源图片链接的资源 HTML 页面的示例:
// androidMain/kotlin/com/example/webview/App.kt
@OptIn(ExperimentalResourceApi::class)
@Composable
@Preview
fun App() {
MaterialTheme {
val uri = Res.getUri("files/webview/index.html")
// Adding a WebView inside AndroidView with layout as full screen.
AndroidView(factory = {
WebView(it).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
}, update = {
it.loadUrl(uri)
})
}
}
该示例适用于以下简单的 HTML 文件:
<html>
<header>
<title>
Cat Resource
</title>
</header>
<body>
<img src="cat.jpg">
</body>
</html>
此示例中的两个资源文件都位于源集中:commonMain
与其他库和资源的交互
从外部库访问多平台资源
如果要使用项目中包含的其他库处理多平台资源,则可以将特定于平台的文件路径传递给这些其他 API。要获取特定于平台的路径,请使用资源的工程路径调用函数:Res.getUri()
val uri = Res.getUri("files/my_video.mp4")
现在,变量包含文件的绝对路径,任何外部库都可以使用该路径以适合它的方式访问文件。uri
对于特定于 Android 的用途,多平台资源也打包为 Android 资产。
远程文件
在资源库的上下文中,只有属于应用程序的文件才被视为资源。
您可以使用专用库使用 Internet 的 URL 从远程文件加载远程文件:
使用 Java 资源
虽然您可以将 Java 资源与 Compose Multiplatform 结合使用,但它们无法从框架提供的扩展功能中受益:生成的访问器、多模块支持、本地化等。考虑完全过渡到多平台资源库以释放这种潜力。
在 Compose Multiplatform 1.7.3 中,软件包中提供的资源 API 已弃用。如果您仍需要使用 Java 资源,请将以下实现复制到您的项目中,以确保您的代码在升级到 Compose Multiplatform 1.7.0 或更高版本后仍能正常工作:compose.ui
@Composable
internal fun painterResource(
resourcePath: String
): Painter = when (resourcePath.substringAfterLast(".")) {
"svg" -> rememberSvgResource(resourcePath)
"xml" -> rememberVectorXmlResource(resourcePath)
else -> rememberBitmapResource(resourcePath)
}
@Composable
internal fun rememberBitmapResource(path: String): Painter {
return remember(path) { BitmapPainter(readResourceBytes(path).decodeToImageBitmap()) }
}
@Composable
internal fun rememberVectorXmlResource(path: String): Painter {
val density = LocalDensity.current
val imageVector = remember(density, path) { readResourceBytes(path).decodeToImageVector(density) }
return rememberVectorPainter(imageVector)
}
@Composable
internal fun rememberSvgResource(path: String): Painter {
val density = LocalDensity.current
return remember(density, path) { readResourceBytes(path).decodeToSvgPainter(density) }
}
private object ResourceLoader
private fun readResourceBytes(resourcePath: String) =
ResourceLoader.javaClass.classLoader.getResourceAsStream(resourcePath).readAllBytes()
下一步是什么?
查看官方演示项目,该项目展示了如何在面向 iOS、Android 和桌面的 Compose Multiplatform 项目中处理资源。
原文地址:https://blog.csdn.net/b275518834/article/details/144811994
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!