使用 JetPack Compose 更改 Android 语言

2024-03-31

我正在尝试使用 jetpack compose 功能更改应用程序的区域设置,如下所示

  @Composable
 fun SetLanguage(position: Int) {
    val locale = Locale(
        when (position) {
            0 -> "ar"
            1 -> "en"
            2 -> "fr"
            else -> {
                "ar"
            }
        }
    )
    Locale.setDefault(locale)
    val configuration = LocalConfiguration.current
    configuration.setLocale(locale)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
        configuration.setLocale(locale)
    else
        configuration.locale = locale
    var resources = LocalContext.current.resources
    resources.updateConfiguration(configuration, resources.displayMetrics)

}

您可以在此处查看工作示例(没有按钮或文本字段)https://github.com/MakeItEasyDev/Jetpack-Compose-Multi-Language-Support https://github.com/MakeItEasyDev/Jetpack-Compose-Multi-Language-Support

但问题是不适用于 OutlinedTextField 或 Button,因为调用此函数时它们不会改变,即使 rightToLeft 支持也不起作用,而且我找不到解决此问题的良好替代方案,因为我无法在项目中重新创建活动


许多开发人员在开始使用 Compose 时遇到的问题是相信当发生重组时,可组合项中的所有内容都会被重组。这不是真的。 Compose 会查看可组合签名并尝试确定自上次调用以来是否有任何更改。仅当参数values更改将调用该函数。在您在 Github 上发布的源代码中,它不包含用于演示问题的按钮或大纲文本字段,因此我添加了一个。当您添加这样的按钮时:

Button(onClick = {}) {
     Text("Do Something")
}

仅当初始组合发生时才会调用按钮内部的文本可组合项。但是当重新组合 Button 时,Text 不会被重新组合,因为 Button 函数中的最后一个参数没有改变。 Lambda 函数不会改变。对于您的情况,更改语言确实会启动按钮的重新组合,但由于最后一个参数不会更改,因此 lambda 内部的内容(在本例中为 Text 可组合项)将永远不会被调用。为了解决这个问题,一种解决方案是使 Text 可组合项使用的字符串资源可变。任何可变的内容都会自动导致任何使用它的可组合项进行重组。

下面的代码是我从你的 Github 项目中获取的并添加了一个按钮。请注意如何使字符串资源 id 变得可变,并且此可变状态在文本中使用:

@Composable
fun LanguageContentPortrait(
    selectedPosition: Int,
    onLanguageSelected: (Int) -> Unit
) {
    val buttonTextResId by remember { mutableStateOf(R.string.hello) }

    CompositionLocalProvider(
        LocalLayoutDirection provides
                if (LocalConfiguration.current.layoutDirection == LayoutDirection.Rtl.ordinal)
                    LayoutDirection.Rtl
                else LayoutDirection.Ltr
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {

            Spacer(modifier = Modifier.height(100.dp))
            ToggleGroup(selectedPosition = selectedPosition, onClick = onLanguageSelected)
            Spacer(modifier = Modifier.height(60.dp))
            Column(
                modifier = Modifier.fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                Text(
                    text = stringResource(id = R.string.content),
                    modifier = Modifier.fillMaxSize(),
                    textAlign = TextAlign.Center
                )

                Button(onClick = {}) {
                    Text(stringResource(buttonTextResId))
                }
            }
        }
    }
}

因此,在任何地方使用尾随 lambda 表达式(包括单击事件处理程序)并且需要进行与语言相关的更改时,您都需要向这些 lambda 内的资源添加可变状态,如上所示。

尽管上述解决方案有效,但我不建议使用它。大多数应用程序都会有很多依赖于语言的组件,并且必须为每个资源字符串创建可变状态将是一件痛苦的事情。更好的解决方案是在语言发生变化时强制整个应用程序重新组合。由于仅 Compose 应用程序通常只是一个 Activity,因此它会导致整个应用程序重新组合。这将确保所有屏幕重新组合并强制所有文本可组合项重新组合,而无需每个屏幕都具有可变状态。您可以通过多种方式强制应用程序重构整个 UI 树。不幸的是,Compose 不包含可让您从头开始重构整个树的 API,因此唯一真正的解决方案是重新启动应用程序。

由于您的应用程序旨在处理设备配置更改(例如语言更改),因此您可能需要查看我开发的专门用于处理设备配置更改的 Compose 框架。它的名字叫Jetmagic。它不仅处理语言更改,还处理所有其他更改,例如屏幕方向、屏幕尺寸、屏幕密度以及与旧的基于视图的系统一起使用的所有其他配置限定符。 Jetmagic 允许您将可组合项视为资源,而不仅仅是一堆函数,并且它处理它们的方式与在基于视图的系统下使用相同算法处理 xml 资源的方式完全相同。包含的示例应用程序还展示了如何更改设备的系统语言(在 Android 的设置下)或通过以编程方式更改语言,使您的可组合 UI 重新组合以正确的语言呈现内容:

https://github.com/JohannBlake/Jetmagic https://github.com/JohannBlake/Jetmagic

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 JetPack Compose 更改 Android 语言 的相关文章

  • 如何自定义菜单项的背景颜色?

    我正在尝试定制Toolbar的弹出菜单 现在我无法设置菜单项的背景颜色 我的 styles xml 如下所示
  • Cheesesquare:enterAlways 会产生错误的布局

    Adding enterAlways到 Cheesesquare 演示的滚动标志
  • AdapterContextMenuInfo 始终为 null

    我尝试通过 android 开发文档中的书来做到这一点 this didn t create a menu i don t know why registerForContextMenu getListView setListAdapter
  • fetchUuidsWithSdp 的奇怪 UUID 逆转

    我有一个在树莓派上运行的 python 蓝牙服务器 使用 PyBluez 我在服务器中使用的uuid是 8f86d132 4ab8 4c15 b8df 0b70cf10ea56 我正在打电话device fetchUuidsWithSdp
  • Recyclerview 动态部分不使用任何第三个库

    我想将标头添加到 recyclerview 我正在尝试使用来实现它 Override public int getItemViewType int position depends on your problem if position 0
  • 将现有 VARCHAR 列与 Room 结合使用

    我正在尝试将现有的数据库与 Android Room 一起使用 但是 我的一个表有一个 VARCHAR 列 Room 似乎只支持 TEXT 不支持 VARCHAR 而且 sqlite 不允许修改列类型 那么 有没有办法使用Room中现有的带
  • Android应用程序组件销毁和重新创建的详细信息

    有人可以向我提供一些具体的 值得信赖的 最好是简洁的 信息 内容如下 系统销毁和 如果适用 重新创建组件的顺序 片段 活动 活动的线程 异步任务 计时器 静态数据 类何时卸载 其他类中的线程 异步任务 定时器 主机 TabActivity
  • 如何更改终端的默认目录?

    我想更改 Android Studio v2 2 2 终端的默认目录 当我打开终端时 它基于项目的目录 C 项目路径 我经常需要使用adb shell 所以我必须导航到 SDK 路径 平台工具 才能使用 adb 命令 是否可以更改终端的默认
  • Dialog.setTitle 不显示标题

    我正在尝试向我的对话框添加自定义标题 但是每当我运行我的应用程序时 它都不会显示标题 我创建对话框的代码是 final Dialog passwordDialog new Dialog this passwordDialog setCont
  • Android 深度链接至 Instagram 应用

    Instagram 已经发布了 iOS 深层链接的 url 方案 但尚未为 Android 创建文档 有没有办法深入链接到 Android 上的 Instagram 应用程序 以转到 Instagram 应用程序中的特定位置 例如 Inst
  • 在 android 中建立与 MySQL 的池连接

    我需要从我的 Android 应用程序访问 MySQL 数据库 现在所有的工作都通过 DriverManager getConnection url 等等 但我必须从多个线程访问数据库 所以我必须使用连接池 问题1 是 com mysql
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • Android 手机作为 GSM 调制解调器在 PC 上发送/接收短信?

    是否可以将 Android 移动设备用作 PC 上的 GSM 调制解调器 我正在 net下开发应用程序来发送 接收短信等 现在我想通过 USB 将我的 Android 设备连接到我的 PC 并将其用作 GSM 调制解调器来与其通信 这里是参
  • Android 构建发布失败,原因为:java.lang.ArrayIndexOutOfBoundsException:213(pr​​oguard 问题)

    我的项目使用调试构建变体构建得很好 但使用发布变体 Android Studio 会抛出 引起原因 java lang ArrayIndexOutOfBoundsException 213 可能是什么问题 如果我设置minifyEnable
  • okhttp 获取失败响应

    我已经在我的 android 客户端中实现了 okhttp 来进行网络调用 当我收到失败响应时 我会收到失败代码以及与该代码相关的文本作为消息 但我没有收到服务器发送给我的自定义失败响应 在我实施的代码中的失败响应中 我收到的消息只是 错误
  • WorkManager 或 AlarmManager 用于日常请求然后通知工作?

    这是用例 用户设置具有特定时间的每日通知 在指定时间 发出网络请求以获取一些数据 然后使用检索到的数据显示通知 我不确定是否应该使用 AlarmManager 还是 WorkManager 来实现这个用例 据我了解 AlarmManager
  • 如何在 Android 中从 WorkManager 取消工作?

    我已经保存了 WorkManagerUUID转换成String在领域数据库中 这是代码 Constraints constraints new Constraints Builder setRequiredNetworkType Netwo
  • Android Studio 缓慢的增量构建

    我已经完成了许多步骤来完善我们的构建系统 those https stackoverflow com questions 16775197 building and running app via gradle and android st
  • 上网本上可以进行Android开发吗? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我想使用我的上网本进行 Android 开发 但是当我尝试使用 Eclipse 运行 SDK 时 没有加载任何内容 上网本对于 Android 开发来
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其

随机推荐