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) {// 保存語言到 SharedPreferencesval 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 {// 獲取保存的語言并更新 Contextval 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 = languageCodeval 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,并應用新的 Configurationval localizedContext = createConfigurationContext(config)// 將新的 Context 應用于當前頁面的 UIval resources = localizedContext.resourcesval displayMetrics = resources.displayMetricsresources.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 = falsediaLog?.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)
將保存結果恢復給掛起函數調用者。