1.需求
实现用户选择语言(未点击下一步),更新当前界面UI,点击下一步后,更新App的语言,并进行保存。
实现目标:
1.设置App的语言,本地进行保存
2.updateResources更新本地语言配置
2.实现代码
1.LanguageManager
object LanguageManager {
private const val PREFS_NAME = "settings"
private const val LANGUAGE_KEY = "language"
fun setLanguage(context: Context, language: String) {
// 保存语言到 SharedPreferences
val sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
sharedPreferences.edit().putString(LANGUAGE_KEY, language).apply()
// 更新资源
updateResources(context, language)
}
fun getSavedLanguage(context: Context): String {
// 如果没有保存语言,默认使用系统语言
val sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
return sharedPreferences.getString(LANGUAGE_KEY, Locale.getDefault().language) ?: Locale.getDefault().language
}
fun applyLanguage(context: Context): Context {
// 获取保存的语言并更新 Context
val language = getSavedLanguage(context)
return updateResources(context, language)
}
private fun updateResources(context: Context, language: String): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val configuration = Configuration(context.resources.configuration)
configuration.setLocale(locale)
return context.createConfigurationContext(configuration)
}
}
2.所有的基类进行设置,记得application在manifest应用
class MyApplication : Application() {
override fun attachBaseContext(base: Context) {
// 应用保存的语言
super.attachBaseContext(LanguageManager.applyLanguage(base))
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// 当配置改变时(如系统语言切换),重新应用用户选择的语言
LanguageManager.applyLanguage(this)
}
}
BaseActivity
所有 Activity 自动应用语言配置:
open class BaseActivity : AppCompatActivity() {
override fun attachBaseContext(newBase: Context) {
// 为每个 Activity 更新语言配置
super.attachBaseContext(LanguageManager.applyLanguage(newBase))
}
}
open class BaseFragment : Fragment() {
override fun onAttach(context: Context) {
super.onAttach(LanguageManager.applyLanguage(context)) // 在这里更新语言
}
}
3.为什么还要在 Activity
里设置语言?
通常,在 Activity
或 Fragment
中设置语言是为了在运行时动态更新语言,尤其是当用户切换语言后,某些界面可能需要重新加载来反映新的语言设置。
关键点:
- 在
Application
中设置语言:可以在应用启动时统一设置默认语言,确保语言配置在整个应用中生效。 - 在
Activity
或Fragment
中设置语言:可以在用户选择语言并希望立即看到语言更改时,确保当前Activity
和Fragment
界面更新。
4.在当前页动态修改语言设置,动态修改文案,但是不点击下一步时,不保存语言选择。
private fun updateLanguage(languageCode: String) {
LogUtils.e("updateLanguage", languageCode)
val finalCode: String = languageCode
val locale =if (languageCode == AppConstants.ZH_HANS) {
Locale("zh","CN")
} else if (languageCode == AppConstants.ZH_HANT) {
Locale("zh","TW")
} else Locale(finalCode)
Locale.setDefault(locale) // 设置默认语言
val config = Configuration(resources.configuration)
config.setLocale(locale) // 修改当前界面语言
// 创建新的 Context,并应用新的 Configuration
val localizedContext = createConfigurationContext(config)
// 将新的 Context 应用于当前页面的 UI
val resources = localizedContext.resources
val displayMetrics = resources.displayMetrics
resources.updateConfiguration(config, displayMetrics)
// 使用新的语言设置刷新当前界面
initData(localizedContext) //界面将刷新以应用新的语言
}
5.其余关键点
1.既然只刷新当前UI,就得生成新的context
localizedContext = createConfigurationContext(config)
2.initData里面就是数据赋值渲染UI,如果调用Activity的recreate方法会闪退,别调用。
6.保存设置退出App
需求:点击语言后,保存语言设置,并且退出App
//点击事件
binding.langCl.setOnClickListener {
diaLog = LanguageBottomSheetFragment { selectedLanguage ->
lifecycleScope.launch {
LogUtils.e("onLanguageSelected", selectedLanguage)
val saveSuccess = saveLanguageSuspend(requireContext(), selectedLanguage)
if (saveSuccess) {
diaLog?.binding?.root?.isEnabled = false
diaLog?.dismiss() // 关闭弹窗
restartApp()
} else {
LogUtils.e("saveLanguage", "Failed to save language")
}
}
}
diaLog?.show(parentFragmentManager, "LanguageBottomSheet")
// VIPBottomSheetFragment().show(parentFragmentManager, "VIPBottomSheet")
}
//保证保存成功
suspend fun saveLanguageSuspend(context: Context, language: String): Boolean {
return suspendCancellableCoroutine { continuation ->
val sharedPreferences =
context.getSharedPreferences(BaseApp.PREFS_NAME, Context.MODE_PRIVATE)
val success = sharedPreferences.edit().putString(LANGUAGE_KEY, language).commit()
continuation.resume(success)
}
}
tips:
1、**suspendCancellableCoroutine**
是 Kotlin 中用于将回调或异步操作转化为挂起函数的工具。它是挂起函数的一部分,可以与协程一起工作,并且能够在协程上下文被取消时进行适当的处理。
2、continuation.resume(success)
将保存结果恢复给挂起函数调用者。