Bas*_*jan 70 android locale right-to-left
就在最近的context.getResources().updateConfiguration()已在Android API 25中弃用,建议使用上下文.而是createConfigurationContext().
有谁知道createConfigurationContext如何用于覆盖android系统区域设置?
在此之前将通过以下方式完成:
Configuration config = getBaseContext().getResources().getConfiguration();
config.setLocale(locale);
context.getResources().updateConfiguration(config,
context.getResources().getDisplayMetrics());
Run Code Online (Sandbox Code Playgroud)
Bas*_*jan 103
受书法的启发,我最终创建了一个上下文包装器.在我的情况下,我需要覆盖系统语言,为我的应用程序用户提供更改应用程序语言的选项,但这可以使用您需要实现的任何逻辑进行自定义.
import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.os.Build;
import java.util.Locale;
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
@SuppressWarnings("deprecation")
public static ContextWrapper wrap(Context context, String language) {
Configuration config = context.getResources().getConfiguration();
Locale sysLocale = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
sysLocale = getSystemLocale(config);
} else {
sysLocale = getSystemLocaleLegacy(config);
}
if (!language.equals("") && !sysLocale.getLanguage().equals(language)) {
Locale locale = new Locale(language);
Locale.setDefault(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setSystemLocale(config, locale);
} else {
setSystemLocaleLegacy(config, locale);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
context = context.createConfigurationContext(config);
} else {
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());
}
return new MyContextWrapper(context);
}
@SuppressWarnings("deprecation")
public static Locale getSystemLocaleLegacy(Configuration config){
return config.locale;
}
@TargetApi(Build.VERSION_CODES.N)
public static Locale getSystemLocale(Configuration config){
return config.getLocales().get(0);
}
@SuppressWarnings("deprecation")
public static void setSystemLocaleLegacy(Configuration config, Locale locale){
config.locale = locale;
}
@TargetApi(Build.VERSION_CODES.N)
public static void setSystemLocale(Configuration config, Locale locale){
config.setLocale(locale);
}
}
Run Code Online (Sandbox Code Playgroud)
并注入您的包装器,在每个活动中添加以下代码:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(MyContextWrapper.wrap(newBase,"fr"));
}
Run Code Online (Sandbox Code Playgroud)
更新10/19/2018 有时在方向更改或活动暂停/恢复后,Configuration对象将重置为默认系统配置,结果我们将看到应用程序显示英语"en"文本,即使我们使用法语"fr"语言环境包装上下文.因此,作为一种良好实践,永远不要将Context/Activity对象保留在活动或片段中的全局变量中.
此外,在MyBaseFragment或MyBaseActivity中创建和使用以下内容:
public Context getMyContext(){
return MyContextWrapper.wrap(getContext(),"fr");
}
Run Code Online (Sandbox Code Playgroud)
这种做法将为您提供100%无错误的解决方案.
com*_*879 24
可能是这样的:
Configuration overrideConfiguration = getBaseContext().getResources().getConfiguration();
overrideConfiguration.setLocales(LocaleList);
Context context = createConfigurationContext(overrideConfiguration);
Resources resources = context.getResources();
Run Code Online (Sandbox Code Playgroud)
奖励:使用createConfigurationContext()的博客文章
Cod*_*meo 24
我已经解决了这个问题,没有创建任何自定义ContextWrapper。
首先我创建了一个扩展函数
fun Context.setAppLocale(language: String): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val config = resources.configuration
config.setLocale(locale)
config.setLayoutDirection(locale)
return createConfigurationContext(config)
}
Run Code Online (Sandbox Code Playgroud)
然后在活动的attachBaseContext方法中,只需将上下文替换为新的上下文即可。
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ContextWrapper(newBase.setAppLocale("bn")))
}
Run Code Online (Sandbox Code Playgroud)
受书法、Mourjan 和我自己的启发,我创造了这个。
首先你必须创建一个Application的子类:
public class MyApplication extends Application {
private Locale locale = null;
@Override
public void onCreate() {
super.onCreate();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
Configuration config = getBaseContext().getResources().getConfiguration();
String lang = preferences.getString(getString(R.string.pref_locale), "en");
String systemLocale = getSystemLocale(config).getLanguage();
if (!"".equals(lang) && !systemLocale.equals(lang)) {
locale = new Locale(lang);
Locale.setDefault(locale);
setSystemLocale(config, locale);
updateConfiguration(config);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (locale != null) {
setSystemLocale(newConfig, locale);
Locale.setDefault(locale);
updateConfiguration(newConfig);
}
}
@SuppressWarnings("deprecation")
private static Locale getSystemLocale(Configuration config) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return config.getLocales().get(0);
} else {
return config.locale;
}
}
@SuppressWarnings("deprecation")
private static void setSystemLocale(Configuration config, Locale locale) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.setLocale(locale);
} else {
config.locale = locale;
}
}
@SuppressWarnings("deprecation")
private void updateConfiguration(Configuration config) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getBaseContext().createConfigurationContext(config);
} else {
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
}
}
}
Run Code Online (Sandbox Code Playgroud)
那么您需要将其设置为您的 AndroidManifest.xml 应用程序标记:
<application
...
android:name="path.to.your.package.MyApplication"
>
Run Code Online (Sandbox Code Playgroud)
并将其添加到您的 AndroidManifest.xml 活动标记中。
<activity
...
android:configChanges="locale"
>
Run Code Online (Sandbox Code Playgroud)
请注意, pref_locale 是这样的字符串资源:
<string name="pref_locale">fa</string>
Run Code Online (Sandbox Code Playgroud)
如果未设置 pref_locale,则硬编码“en”是默认语言
这里没有 100% 有效的解决方案。您需要同时使用createConfigurationContext和applyOverrideConfiguration。否则,即使您用baseContext新配置替换每个活动,活动仍将使用旧区域Resources设置。ContextThemeWrapper
这是我的解决方案,适用于 API 29:
从以下类别对您的MainApplication班级进行子类化:
abstract class LocalApplication : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(
base.toLangIfDiff(
PreferenceManager
.getDefaultSharedPreferences(base)
.getString("langPref", "sys")!!
)
)
}
}
Run Code Online (Sandbox Code Playgroud)
还有来自Activity:
abstract class LocalActivity : AppCompatActivity() {
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(
PreferenceManager
.getDefaultSharedPreferences(base)
.getString("langPref", "sys")!!
)
}
override fun applyOverrideConfiguration(overrideConfiguration: Configuration) {
super.applyOverrideConfiguration(baseContext.resources.configuration)
}
}
Run Code Online (Sandbox Code Playgroud)
添加LocaleExt.kt下一个扩展功能:
const val SYSTEM_LANG = "sys"
const val ZH_LANG = "zh"
const val SIMPLIFIED_CHINESE_SUFFIX = "rCN"
private fun Context.isAppLangDiff(prefLang: String): Boolean {
val appConfig: Configuration = this.resources.configuration
val sysConfig: Configuration = Resources.getSystem().configuration
val appLang: String = appConfig.localeCompat.language
val sysLang: String = sysConfig.localeCompat.language
return if (SYSTEM_LANG == prefLang) {
appLang != sysLang
} else {
appLang != prefLang
|| ZH_LANG == prefLang
}
}
fun Context.toLangIfDiff(lang: String): Context =
if (this.isAppLangDiff(lang)) {
this.toLang(lang)
} else {
this
}
@Suppress("DEPRECATION")
fun Context.toLang(toLang: String): Context {
val config = Configuration()
val toLocale = langToLocale(toLang)
Locale.setDefault(toLocale)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.setLocale(toLocale)
val localeList = LocaleList(toLocale)
LocaleList.setDefault(localeList)
config.setLocales(localeList)
} else {
config.locale = toLocale
}
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
config.setLayoutDirection(toLocale)
this.createConfigurationContext(config)
} else {
this.resources.updateConfiguration(config, this.resources.displayMetrics)
this
}
}
/**
* @param toLang - two character representation of language, could be "sys" - which represents system's locale
*/
fun langToLocale(toLang: String): Locale =
when {
toLang == SYSTEM_LANG ->
Resources.getSystem().configuration.localeCompat
toLang.contains(ZH_LANG) -> when {
toLang.contains(SIMPLIFIED_CHINESE_SUFFIX) ->
Locale.SIMPLIFIED_CHINESE
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ->
Locale(ZH_LANG, "Hant")
else ->
Locale.TRADITIONAL_CHINESE
}
else -> Locale(toLang)
}
@Suppress("DEPRECATION")
private val Configuration.localeCompat: Locale
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
this.locales.get(0)
} else {
this.locale
}
Run Code Online (Sandbox Code Playgroud)
添加到res/values/arrays.xml数组中您支持的语言:
<string-array name="lang_values" translatable="false">
<item>sys</item> <!-- System default -->
<item>ar</item>
<item>de</item>
<item>en</item>
<item>es</item>
<item>fa</item>
...
<item>zh</item> <!-- Traditional Chinese -->
<item>zh-rCN</item> <!-- Simplified Chinese -->
</string-array>
Run Code Online (Sandbox Code Playgroud)
我想提一下:
config.setLayoutDirection(toLocale);当您使用阿拉伯语、波斯语等 RTL 语言环境时,用于更改布局方向。"sys"代码中的值表示“继承系统默认语言”。ContextWraper返回的新上下文createConfigurationContextcreateConfigurationContext您应该传递从头开始创建的配置,并且仅包含Locale属性集。不应为此配置设置任何其他属性。因为如果我们为此配置设置一些其他属性(例如方向),我们将永远覆盖该属性,并且即使我们旋转屏幕,我们的上下文也不再更改该方向属性。recreate,因为 applicationContext 将保留旧的语言环境,并且可能会提供意外的行为。因此,监听首选项更改并重新启动整个应用程序任务:fun Context.recreateTask() {
this.packageManager
.getLaunchIntentForPackage(context.packageName)
?.let { intent ->
val restartIntent = Intent.makeRestartActivityTask(intent.component)
this.startActivity(restartIntent)
Runtime.getRuntime().exit(0)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
47580 次 |
| 最近记录: |