• KMP中的资源处理(字符串,图片等)


    前言

    安卓开发者的视角,资源有很多种类,不过常用的是这几种

    KMP中的UI一般用Compose

    其中的anim,layout,colors,themes都使用代码的形式实现

    而KMP中目前貌似没有通用的字符串和图片资源管理和获取的方式,于是我们自己实现一下

    正文

    字符串资源

    字符串的实现我的实现很简单,就是直接用一个单例类来记录各种字符串资源

    大概实现是这样:

    1. /**
    2. * creator: lt
    3. * effect : 字符串资源
    4. * warning:
    5. */
    6. object Strings {
    7. val separator: String
    8. //单词间的分隔符
    9. get() {
    10. return when (LanguageManager.currLanguage) {
    11. EN -> " "
    12. ZH -> ""
    13. }
    14. }
    15. val respose_error: String
    16. get() {
    17. return when (LanguageManager.currLanguage) {
    18. EN -> "Server error, please try again later!"
    19. ZH -> "服务器错误,请稍后再试!"
    20. }
    21. }
    22. }

    其中 LanguageManager.currLanguage 是一个自定义的state,所以文本是可以响应式的根据语言改变app内的文本的(ps:可以这么做,不过目前我是用的是隐式参数的方式)

    使用方式为:

    Text(Strings.respose_error)

    简单方便

    图片资源

    图片资源我们也可以像字符串资源一样使用代码的形式来实现

    实现方式:

    1. object Painters {
    2. val select: Painter
    3. @Composable
    4. get() = PainterGenerator.generate("select", "")
    5. val back: Painter
    6. @Composable
    7. get() {
    8. return when (LanguageManager.currLanguage) {
    9. EN -> PainterGenerator.generate("back", "")
    10. ZH -> PainterGenerator.generate("back", "zh")
    11. }
    12. }
    13. }

    select是单语言时的形式,back是有多种语言时的形式,同样可以响应式的根据语言自动切换图片

    使用方式:

    Image(Painters.back,null)

    同样很简单

    然后我们看一下 PainterGenerator.generate 是怎么实现的

    common:

    1. /**
    2. * creator: lt
    3. * effect : Painter生成器,用于生成静态的图片资源
    4. * warning:
    5. */
    6. expect object PainterGenerator {
    7. /**
    8. * 生成Painter
    9. * drawable-zh-xxhdpi/ic_launcher.webp
    10. * [imageName]文件名: ic_launcher
    11. * [languageName]资源的语言: zh 如果zh目录中没有,则需传空字符串(要保证传的资源的语言的目录中要有这个图片才行)
    12. */
    13. @Composable
    14. fun generate(
    15. imageName: String,
    16. languageName: String,
    17. ): Painter
    18. }

    android:

    1. actual object PainterGenerator {
    2. private var currLocale =
    3. private val androidResource =
    4. Resources(
    5. app.assets,
    6. app.resources.displayMetrics,
    7. Configuration(app.resources.configuration)
    8. )
    9. /**
    10. * 生成Painter
    11. * drawable-zh-xxhdpi/ic_launcher.webp
    12. * [imageName]文件名: ic_launcher
    13. * [languageName]资源的语言: zh
    14. */
    15. @Composable
    16. actual fun generate(
    17. imageName: String,
    18. languageName: String
    19. ): Painter = remember(imageName, languageName) {
    20. //如果没有指定语言,就是用默认语言的图片,如果指定了语言,就设置一下资源的语言
    21. if (languageName.isEmpty())
    22. androidResource.configuration.setLocale(currLocale)
    23. else
    24. androidResource.configuration.setLocale(Locale(languageName))
    25. //获取drawable的id
    26. val id = ExceptionUtil.releaseCatchThrowable({
    27. androidResource.getIdentifier(
    28. imageName, "drawable", app.packageName
    29. )
    30. }) ?: R.drawable.load_error
    31. //根据id,使用带有语言设置的资源来加载
    32. BitmapPainter(
    33. androidResource.getDrawable(id).asT().bitmap.asImageBitmap()
    34. )
    35. }
    36. }

    安卓的实现复杂一些,其实就是通过 resource 对象的 getIdentifier 方法,然后设置相应的语言并通过文件夹名和文件名来找到相应的资源id,并加载,然后将bitmap转换为相应资源

    ps:使用此方式安卓不能混淆资源名和混淆移除无用的resource文件

    desktop 和 iOS:

    1. actual object PainterGenerator {
    2. /**
    3. * 生成Painter
    4. * drawable-zh-xxhdpi/ic_launcher.webp
    5. * [imageName]文件名: ic_launcher
    6. * [languageName]资源的语言: zh
    7. */
    8. @Composable
    9. actual fun generate(
    10. imageName: String,
    11. languageName: String
    12. ): Painter = painterResource(remember(imageName, languageName) {
    13. "drawable%s-xxhdpi/%s.webp".format(
    14. if (languageName.isEmpty()) "" else "-$languageName",
    15. imageName
    16. )
    17. })
    18. }

    desktop和iOS没啥说的,其实就是用了自带的api,内部是通过classLoder(desktop)加载的资源

    js:

    1. actual object PainterGenerator {
    2. /**
    3. * 生成Painter
    4. * drawable-zh-xxhdpi/ic_launcher.webp
    5. * [imageName]文件名: ic_launcher
    6. * [languageName]资源的语言: zh
    7. */
    8. @OptIn(ExperimentalResourceApi::class)
    9. @Composable
    10. actual fun generate(
    11. imageName: String,
    12. languageName: String
    13. ): Painter {
    14. val state: MutableState> =
    15. remember(imageName, languageName) { mutableStateOf(LoadState.Loading()) }
    16. LaunchedSafeEffect(imageName, languageName) {
    17. state.value = try {
    18. LoadState.Success(
    19. resource(
    20. "drawable%s-xxhdpi/%s.webp".format(
    21. if (languageName.isEmpty()) "" else "-$languageName",
    22. imageName
    23. )
    24. ).readBytes()
    25. .toImageBitmap()
    26. )
    27. } catch (e: Exception) {
    28. e.w()
    29. LoadState.Error(e)
    30. }
    31. }
    32. return BitmapPainter(state.value.orEmpty())
    33. }
    34. }

    js的实现也是使用了自带的api,不过是异步的,因为内部是走的网络请求加载的资源

    然后我们可以通过配置资源目录,将每个端的资源目录指向一个目录

    这样就实现了图片资源管理的功能

    ps:其实图片资源的类我们完全可以通过ksp去生成,不过这不是这篇文章的重点,感兴趣的同学可以自己动手试试,参考:使用KSP处理注解和生成Kotlin代码

    end

    对Kotlin或KMP感兴趣的同学可以进Q群 101786950

    如果这篇文章对您有帮助的话

    可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

  • 相关阅读:
    第十四届蓝桥杯第二期模拟赛题解
    基于自定义表编写认证类、django-jwt源码分析、权限介绍、simpleui的使用
    算法与数据结构 --- 排序 --- 交换排序 与 选择排序
    vue_router_webpack_imported_module_0__.define is not a constru
    GRU的 电影评论情感分析 - python 深度学习 情感分类 计算机竞赛
    十二月第一场雪
    Linux中配置sudo用户访问权限
    Android开发常见问题收集(长期更新)
    Tensor Core的WMMA API编程入门
    【基础教程】Matlab实现指数威布尔分布
  • 原文地址:https://blog.csdn.net/qq_33505109/article/details/134019095