资源和布局方向仅在 Android 8.0 及更高版本上呈现错误 [英] Resources and layout direction rendered incorrectly only on Android 8.0 and above

查看:37
本文介绍了资源和布局方向仅在 Android 8.0 及更高版本上呈现错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个多语言应用,主要语言为英语,次要语言为阿拉伯语.

我在应用程序中每个 ActivityonCreate() 中调用 setLocale():

public static void setLocale(Locale locale){Locale.setDefault(locale);上下文上下文 = MyApplication.getInstance();最终资源资源 = context.getResources();最终配置 config = resources.getConfiguration();config.setLocale(locale);context.getResources().updateConfiguration(config,resources.getDisplayMetrics());}

其中 locale 是以下之一:

上述方法在之前被调用 super.onCreate(savedInstanceState) 被调用.

在所有 8.0+ 的设备上,相同的屏幕看起来像这样:

这是错误.

<块引用>

事实证明,方向和资源都得到了显示不正确.

这里有两个问题:

  • 正确的Locale 似乎没有在整个应用配置中更新.
  • 文本和可绘制对象的方向与其应有的方向相反.

关于方向,一个奇怪的方法叫做 setLayoutDirection() 存在,我以前没有注意到.

我想知道这个问题是什么,为什么会在奥利奥发生,以及解决方法是什么.请对此提供帮助/评论.

编辑:

<块引用>

根据API差异报告<代码>更新配置()方法确实在 Android 7.1(API 级别 25)中被弃用了.

另外,找到了所有相关的帖子.按重要性排序:

1. Android N 以编程方式更改语言.

2. Android context.getResources.updateConfiguration() 已弃用.

3. 如何更改 Android O/Oreo/api 26 应用语言.

4. API 24 及更高版本中的 Android RTL 问题在区域设置更改时出现

5. 以编程方式更改语言(Android N 7.0 - API 24).

6. Android N - 在运行时更改区域设置.

7. Android Oreo 中的 RTL 布局错误.

解决方案

这个问题的完整解决方案包括三个步骤:

第 1 步:

BaseActivity(或所有Activity)的onCreate()中,设置Locale如下:

@Overrideprotected void onCreate(Bundle savedInstanceState) {//首先设置 LocaleUtils.setLocale(Utils.getSavedLocale());requestWindowFeature(Window.FEATURE_NO_TITLE);super.onCreate(savedInstanceState);............}

其中 getSavedLocale() 是与当前区域对应的 Locale(这将特定于您的项目......).

Utils.setLocale(...) 方法定义如下:

public static void setLocale(Locale locale){上下文上下文 = MyApplication.getInstance();资源资源 = context.getResources();配置配置 = resources.getConfiguration();Locale.setDefault(locale);configuration.setLocale(locale);configuration.setLayoutDirection(locale);//updateConfiguration(...) 在 N 中被弃用如果(Build.VERSION.SDK_INT >= 25){context = context.getApplicationContext().createConfigurationContext(configuration);context = context.createConfigurationContext(configuration);}context.getResources().updateConfiguration(configuration,resources.getDisplayMetrics());}

这会在每个 Activity 中设置正确的 Locale.这对于支持 API 级别 25 的应用程序来说已经足够了.对于 API 级别 26 &如上所述,还需要执行第 2 步和第 3 步.

第 2 步:

在您的 BaseActivity 中重写以下方法:

@Overrideprotected void attachBaseContext(Context newBase) {newBase = Utils.getLanguageAwareContext(newBase);super.attachBaseContext(newBase);}

其中函数 getLanguageAwareContext(...) 定义如下:

public static Context getLanguageAwareContext(Context context){配置配置 = context.getResources().getConfiguration();语言环境 locale = getIntendedLocale();configuration.setLocale(locale);configuration.setLayoutDirection(locale);返回 context.createConfigurationContext(configuration);}

这与第 1 步一起,为 API 级别 26 及更高级别在您应用的每个 Activity 中设置正确的 Locale.

然而,正确设置语言方向还需要一个步骤......

第 3 步:

在您的 BaseActivityonCreate() 中,添加以下代码:

@Overrideprotected void onCreate(Bundle savedInstanceState) {........//是的,这是一个合法的错误... :)如果(Build.VERSION.SDK_INT >= 26){getWindow().getDecorView().setLayoutDirection(Utils.isRTL()?View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);}........}

其中 isRTL() 函数定义如下:

public static boolean isRTL(){return TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;}

上述步骤应解决所有现有 Android 版本上的所有问题(至少与设置 Locale 和文本方向有关).

I have a multilingual app with primary language English and secondary language Arabic.

I am calling setLocale() in the onCreate() of every Activity in my app:

public static void setLocale(Locale locale){
    Locale.setDefault(locale);
    Context context = MyApplication.getInstance();
    final Resources resources = context.getResources();
    final Configuration config = resources.getConfiguration();
    config.setLocale(locale);
    context.getResources().updateConfiguration(config,
            resources.getDisplayMetrics());
}

where locale is one of the following:

The above method is called before super.onCreate(savedInstanceState) gets called.

As described in the documentation,

  • I have added android:supportsRtl="true" in the manifest.
  • I have changed all xml properties with left and right attributes to start and end respectively.
  • I have put Arabic-language strings in resvalues-arstrings folder and drawable resources in resdrawable-ar folder (and similarly for other resources).

The above setup works properly. After changing the Locale to ar-AE, Arabic text & resources are correctly displayed in my Activities.

However, there is a problem with both resources and layout direction for all Android devices with version 8.0 and above.

On a device with version less than 8.0, an RTL screen correctly looks like this:

And on all devices with 8.0+, the same screen turns up looking like this:

which is wrong.

It turns out that both the direction and the resources are getting displayed incorrectly.

There are two problems here:

  • The correct Locale does not seem to be updated across the app configuration.
  • The direction of the text and drawables is opposite of what it should be.

With respect to direction, a curious method called setLayoutDirection() exists which I had not noticed before.

I would like to know what this problem is, why it happens in Oreo and what is the solution for it. Please help / comment on this.

EDIT:

According to the API Differences report, the updateConfiguration() method was indeed deprecated in Android 7.1 (API level 25).

Also, found all the relevant posts on this. In order of importance:

1. Android N change language programmatically.

2. Android context.getResources.updateConfiguration() deprecated.

3. How to change Android O / Oreo / api 26 app language.

4. Android RTL issue in API 24 and higher on locale change

5. Change language programmatically (Android N 7.0 - API 24).

6. Android N - Change Locale in runtime.

7. RTL layout bug in android Oreo.

解决方案

The complete solution to this problem consists of three steps:

STEP 1:

In the onCreate() of your BaseActivity (or all your Activitys), set the Locale as follows:

@Override
protected void onCreate(Bundle savedInstanceState) {

    // set the Locale the very first thing
    Utils.setLocale(Utils.getSavedLocale());
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);

    ......
    ......

}

where getSavedLocale() is the Locale corresponding to the current region (this will be specific for your project ... ).

And the method Utils.setLocale(...) is defined as follows:

public static void setLocale(Locale locale){
    Context context = MyApplication.getInstance();
    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();
    Locale.setDefault(locale);
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);

    // updateConfiguration(...) is deprecated in N
    if (Build.VERSION.SDK_INT >= 25) {
        context = context.getApplicationContext().createConfigurationContext(configuration);
        context = context.createConfigurationContext(configuration);
    }

    context.getResources().updateConfiguration(configuration,
            resources.getDisplayMetrics());
}

This sets the correct Locale in every Activity. This is enough for apps supporting API level 25. For API level 26 & above, STEP 2 and STEP 3 are also required.

STEP 2:

Override the following method in your BaseActivity:

@Override
protected void attachBaseContext(Context newBase) {
    newBase = Utils.getLanguageAwareContext(newBase);
    super.attachBaseContext(newBase);
}

where the function getLanguageAwareContext(...) is defined as follows:

public static Context getLanguageAwareContext(Context context){
    Configuration configuration = context.getResources().getConfiguration();
    Locale locale = getIntendedLocale();
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);
    return context.createConfigurationContext(configuration);
}

This, along with STEP 1, sets the correct Locale in every Activity of your app for API level 26 and above.

One more step, however, is required for setting the language direction correctly ...

STEP 3:

In the onCreate() of your BaseActivity, add the following code:

@Override
protected void onCreate(Bundle savedInstanceState) {

    ....
    ....

    // yup, it's a legit bug ... :)
    if (Build.VERSION.SDK_INT >= 26) {
        getWindow().getDecorView().setLayoutDirection(Utils.isRTL()
                ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);


    }

    ....
    ....
}

where the isRTL() function is defined as follows:

public static boolean isRTL(){
    return TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
}

The above steps should take care of all issues (at least regarding setting the Locale and text direction) on all extant versions of Android.

这篇关于资源和布局方向仅在 Android 8.0 及更高版本上呈现错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆