Android 在应用程序本身内更改区域设置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2264874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Changing Locale within the app itself
提问by Hubert
My users can change the Locale within the app (they may want to keep their phone settings in English but read the content of my app in French, Dutch or any other language ...)
我的用户可以在应用程序中更改区域设置(他们可能希望将手机设置保留为英语,但使用法语、荷兰语或任何其他语言阅读我的应用程序内容......)
Why is this working perfectly fine in 1.5/1.6 but NOT in 2.0 anymore ???
为什么这在 1.5/1.6 中工作得很好,但不再在 2.0 中????
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case 201:
Locale locale2 = new Locale("fr");
Locale.setDefault(locale2);
Configuration config2 = new Configuration();
config2.locale = locale2;
getBaseContext().getResources().updateConfiguration(
config2, getBaseContext().getResources().getDisplayMetrics());
// loading data ...
refresh();
// refresh the tabs and their content
refresh_Tab ();
break;
case 201: etc...
The problem is that the MENU "shrinks" more and more everytime the user is going through the lines of code above ...
问题是每次用户浏览上面的代码行时,菜单“缩小”得越来越多......
This is the Menu that gets shrunk:
这是缩小的菜单:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 100, 1, "REFRESH").setIcon(android.R.drawable.ic_menu_compass);
SubMenu langMenu = menu.addSubMenu(0, 200, 2, "NL-FR").setIcon(android.R.drawable.ic_menu_rotate);
langMenu.add(1, 201, 0, "Nederlands");
langMenu.add(1, 202, 0, "Fran?ais");
menu.add(0, 250, 4, R.string.OptionMenu2).setIcon(android.R.drawable.ic_menu_send);
menu.add(0, 300, 5, R.string.OptionMenu3).setIcon(android.R.drawable.ic_menu_preferences);
menu.add(0, 350, 3, R.string.OptionMenu4).setIcon(android.R.drawable.ic_menu_more);
menu.add(0, 400, 6, "Exit").setIcon(android.R.drawable.ic_menu_delete);
return super.onCreateOptionsMenu(menu);
}
What should I do in API Level 5 to make this work again ?
我应该在 API 级别 5 中做什么才能使这项工作再次发挥作用?
HERE IS THE FULL CODE IF YOU WANT TO TEST THIS :
如果你想测试这个,这里是完整的代码:
import java.util.Locale;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.widget.Toast;
public class Main extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
SubMenu langMenu = menu.addSubMenu(0, 200, 2, "NL-FR").setIcon(android.R.drawable.ic_menu_rotate);
langMenu.add(1, 201, 0, "Nederlands");
langMenu.add(1, 202, 0, "Fran?ais");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case 201:
Locale locale = new Locale("nl");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
Toast.makeText(this, "Locale in Nederlands !", Toast.LENGTH_LONG).show();
break;
case 202:
Locale locale2 = new Locale("fr");
Locale.setDefault(locale2);
Configuration config2 = new Configuration();
config2.locale = locale2;
getBaseContext().getResources().updateConfiguration(config2, getBaseContext().getResources().getDisplayMetrics());
Toast.makeText(this, "Locale en Fran?ais !", Toast.LENGTH_LONG).show();
break;
}
return super.onOptionsItemSelected(item);
}
}
AND HERE IS THE MANIFEST :
这是清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cousinHub.ChangeLocale"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
THIS IS WHAT I FOUND :
这就是我发现的:
<uses-sdk android:minSdkVersion="5" />
=> IT WORKS JUST FINE ...
=> 它工作得很好......
<uses-sdk android:minSdkVersion="3" />
=> Menu shrinks every time you change the locale !!!
=> 每次更改语言环境时菜单都会缩小!!!
as I want to keep my application accessible for users on 1.5, what should I do ??
因为我想让 1.5 上的用户可以访问我的应用程序,我该怎么办?
采纳答案by Hubert
After a good night of sleep, I found the answer on the Web (a simple Google search on the following line "getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics());
"), here it is :
一夜好眠后,我在网上找到了答案(简单的谷歌搜索下一行“ getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics());
”),这里是:
link text=> this link also shows screenshots
of what is happening !
链接文本=> 此链接还显示screenshots
了正在发生的事情!
Density was the issue here, I needed to have this in the AndroidManifest.xml
密度是这里的问题,我需要在 AndroidManifest.xml 中有这个
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:anyDensity="true"
/>
The most important is the android:anyDensity =" true ".
最重要的是android:anyDensity =" true "。
Don't forget to add the following in the AndroidManifest.xml
for every activity (for Android 4.1 and below):
不要忘记在AndroidManifest.xml
for each Activity 中添加以下内容(适用于 Android 4.1 及以下):
android:configChanges="locale"
This version is needed when you build for Android 4.2 (API level 17) explanation here:
当您为 Android 4.2(API 级别 17)构建时需要此版本的说明:
android:configChanges="locale|layoutDirection"
回答by Andrey Novikov
Through the original question is not exactly about the locale itself all other locale related questions are referencing to this one. That's why I wanted to clarify the issue here. I used this question as a starting point for my own locale switching code and found out that the method is not exactly correct. It works, but only until any configuration change (e.g. screen rotation) and only in that particular Activity. Playing with a code for a while I have ended up with the following approach:
通过原始问题并不完全是关于语言环境本身,所有其他与语言环境相关的问题都引用了这个问题。这就是为什么我想在这里澄清这个问题。我使用这个问题作为我自己的语言环境切换代码的起点,发现该方法并不完全正确。它有效,但仅在任何配置更改(例如屏幕旋转)之前,并且仅在该特定活动中。玩了一段时间的代码,我最终采用了以下方法:
I have extended android.app.Application and added the following code:
我扩展了 android.app.Application 并添加了以下代码:
public class MyApplication extends Application
{
private Locale locale = null;
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
if (locale != null)
{
newConfig.locale = locale;
Locale.setDefault(locale);
getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
}
}
@Override
public void onCreate()
{
super.onCreate();
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
Configuration config = getBaseContext().getResources().getConfiguration();
String lang = settings.getString(getString(R.string.pref_locale), "");
if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang))
{
locale = new Locale(lang);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
}
}
}
This code ensures that every Activity will have custom locale set and it will not be reset on rotation and other events.
此代码确保每个 Activity 都将设置自定义区域设置,并且不会在旋转和其他事件时重置。
I have also spent a lot of time trying to make the preference change to be applied immediately but didn't succeed: the language changed correctly on Activity restart, but number formats and other locale properties were not applied until full application restart.
我还花了很多时间尝试立即应用首选项更改,但没有成功:语言在 Activity 重新启动时正确更改,但数字格式和其他区域设置属性直到完整的应用程序重新启动后才应用。
Changes to AndroidManifest.xml
更改为 AndroidManifest.xml
Don't forget to add android:configChanges="layoutDirection|locale"
to every activity at AndroidManifest, as well as the android:name=".MyApplication"
to the <application>
element.
不要忘记添加android:configChanges="layoutDirection|locale"
为每一个活动在AndroidManifest,以及android:name=".MyApplication"
到<application>
元素。
回答by Roberto B.
In Android M the top solution won't work. I've written a helper class to fix that which you should call from your Application class and all Activities (I would suggest creating a BaseActivity and then make all the Activities inherit from it.
在 Android M 中,顶级解决方案不起作用。我编写了一个辅助类来修复您应该从 Application 类和所有活动中调用的内容(我建议创建一个 BaseActivity,然后让所有活动都继承自它。
Note: This will also support properly RTL layout direction.
注意:这也将支持正确的 RTL 布局方向。
Helper class:
辅助类:
public class LocaleUtils {
private static Locale sLocale;
public static void setLocale(Locale locale) {
sLocale = locale;
if(sLocale != null) {
Locale.setDefault(sLocale);
}
}
public static void updateConfig(ContextThemeWrapper wrapper) {
if(sLocale != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Configuration configuration = new Configuration();
configuration.setLocale(sLocale);
wrapper.applyOverrideConfiguration(configuration);
}
}
public static void updateConfig(Application app, Configuration configuration) {
if (sLocale != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
//Wrapping the configuration to avoid Activity endless loop
Configuration config = new Configuration(configuration);
// We must use the now-deprecated config.locale and res.updateConfiguration here,
// because the replacements aren't available till API level 24 and 17 respectively.
config.locale = sLocale;
Resources res = app.getBaseContext().getResources();
res.updateConfiguration(config, res.getDisplayMetrics());
}
}
}
Application:
应用:
public class App extends Application {
public void onCreate(){
super.onCreate();
LocaleUtils.setLocale(new Locale("iw"));
LocaleUtils.updateConfig(this, getBaseContext().getResources().getConfiguration());
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LocaleUtils.updateConfig(this, newConfig);
}
}
BaseActivity:
基本活动:
public class BaseActivity extends Activity {
public BaseActivity() {
LocaleUtils.updateConfig(this);
}
}
回答by trgraglia
This is for my comment on Andrey's answer but I cant include code in the comments.
这是我对安德烈回答的评论,但我不能在评论中包含代码。
Is you preference activity being called from you main activity? you could place this in the on resume...
您是否从主要活动中调用了偏好活动?你可以把它放在简历上...
@Override
protected void onResume() {
if (!(PreferenceManager.getDefaultSharedPreferences(
getApplicationContext()).getString("listLanguage", "en")
.equals(langPreference))) {
refresh();
}
super.onResume();
}
private void refresh() {
finish();
Intent myIntent = new Intent(Main.this, Main.class);
startActivity(myIntent);
}
回答by nikib3ro
I couldn't used android:anyDensity="true" because objects in my game would be positioned completely different... seems this also does the trick:
我不能使用 android:anyDensity="true" 因为我的游戏中的对象将被定位完全不同......似乎这也能解决问题:
// creating locale Locale locale2 = new Locale(loc); Locale.setDefault(locale2); Configuration config2 = new Configuration(); config2.locale = locale2; // updating locale mContext.getResources().updateConfiguration(config2, null);
回答by Ramesh Akula
If you want to effect on the menu options for changing the locale immediately.You have to do like this.
如果您想立即影响菜单选项以更改语言环境。您必须这样做。
//onCreate method calls only once when menu is called first time.
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
//1.Here you can add your locale settings .
//2.Your menu declaration.
}
//This method is called when your menu is opend to again....
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
menu.clear();
onCreateOptionsMenu(menu);
return super.onMenuOpened(featureId, menu);
}