强制应用程序使用RTL布局方向无效

27

我正在尝试在我的应用程序中添加RTL语言支持(目前具体是阿拉伯语)。我也将支持英语。我已经完成了以下步骤:

  • 将minSdkVersion设置为17
  • AndroidManifest.xml中的应用程序标签中添加android:supportsRtl="true"
  • 将我的左/右属性切换为start/end

起初,我手动进行了这些更改,然后我使用了Android Studio的“重构->尽可能添加RTL支持...”菜单项。

当我预览布局文件时,我可以看到RTL预览正确地镜像UI。但是,即使我使用“强制RTL布局方向”,我的应用程序也不会显示RTL布局。系统UI被翻转,因此该选项通常有效。

是否还有其他事项需要处理以显示RTL布局?我希望我没有漏掉什么显而易见的东西。我在API 21模拟器上测试了这个。

更新

我继承了部分代码。可能有些设置被覆盖并强制进入LTR模式。我创建了一个测试应用程序来测试RTL模式,它可以正常工作。什么样的代码会导致“Force RTL Layout Direction”设置被忽略(或被覆盖)?

更新2

我已经检查了区域设置是否正确设置,并且确实如此。我还检查了配置,ldrtl被设置。我在签名的apk文件中验证了android:supportsRtl是否被包含,并且没有任何布局文件有android:layoutDirection="ltr"。我甚至尝试手动添加android:layoutDirection="rtl"来强制镜像布局,但这也没有起作用。

更新3

我向项目中添加了另一个活动,将其设置为启动活动,并确保它未连接到任何现有代码。它是 Activity 的一个子类。问题仍然存在。因此理论上这是一个配置问题。正如我所说,我检查了 AndroidManifest.xml 文件和所有生成的布局文件,RTL 支持和布局更改都已添加进去了。配置可能出了什么问题?


嗨@Ben Kane,你解决了这个问题吗?我也遇到了完全相同的问题。我强制将所有内容转换为RTL,尽我所能去做一切,但是当我打印出view.getLayoutDirection()的值时,它仍然是LTR。 - namanhams
嗨@namanhams。是的,我做到了!请查看我发布并接受的答案。在代码中搜索&=。具体行在注释中。我真的应该将其添加到我的答案中。这是由于从Android开发者博客文章中复制代码时出现错误导致的,该文章是关于检查是否在调试模式下运行的。 - Ben Kane
2个回答

13

最难以捉摸的bug。如我在问题中提到的,这段代码大部分是继承而来的。结果发现这是一个按位运算符问题,它搞乱了应用程序的标志。使用&=检查标志是否设置,而不是使用&

正如评论中所指出的那样,该代码取自Android Developers博客文章中的示例,这也解释了为什么有这么多人遇到了相同的问题。我提交了一个错误报告,博客文章此后已被悄悄地更新。以下是原始代码,我从中删除了&=请勿直接使用以下代码。你需要将&=更改为&

isDebuggable = (appContext.getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0;

1
遇到了完全相同的问题。在我调用的一个类中,我这样写:isDebuggable = (appContext.getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0;请注意,使用的是 &= 而不是 & - Arjan Mels
1
@arjan 可能是从这里得到的:https://dev59.com/Bmw05IYBdhLWcg3wsz0l#7089300。那个答案最初有赋值。而且两年都没有被编辑:( 所以很多人可能在他们的代码中有这个错误。我稍后会在我的答案中详细说明。目前不在电脑旁。 - Ben Kane
3
哇,那段代码最初是在这篇Android开发者博客文章中发现的:http://android-developers.blogspot.com/2010/09/securing-android-lvl-applications.html。太糟糕了 :( 我会看看是否可以联系他们修复它。 - Ben Kane
不错的侦探工作!那确实可能是我得到这行代码的地方。谢谢你注意到了这一点。 - Arjan Mels
我现在看到博客文章更新不是静默的(不确定最初是否错过了这一点或者他们事后添加了)。"2016年6月23日更新-对“使您的应用程序防篡改”的代码片段进行了编辑",即此片段。 - Ben Kane
显示剩余3条评论

2

试试这个...

  1. Create a class to maintain global application state.

     public class YourGlobalClass extends Application {
    
       @Override
       public void onCreate() {
       updateLanguage(this, null);
       super.onCreate();
       }
    
     public static void updateLanguage(Context ctx, String lang) {
    
      Configuration cfg = new Configuration();
      LocalSharedManager manager = new LocalSharedManager(ctx);
      String language = manager.GetValueFromSharedPrefs("force_locale");
    
         if (TextUtils.isEmpty(language) && lang == null) {
            cfg.locale = Locale.getDefault();
            String tmp_locale = "";
            tmp_locale = Locale.getDefault().toString().substring(0, 2);
            manager.SaveValueToSharedPrefs("force_locale", tmp_locale);
    
        } else if (lang != null) {
            cfg.locale = new Locale(lang);
            manager.SaveValueToSharedPrefs("force_locale", lang);
    
        } else if (!TextUtils.isEmpty(language)) {
            cfg.locale = new Locale(language);
        }
        ctx.getResources().updateConfiguration(cfg, null);
       }
    
     }
    
  2. Specify global class to your AndroidManifest.xml's tag, which will cause that class to be instantiated with your saved locale, when the process for your application/package is created. Like, android:name="com.your.package.YourGlobalClass" android:supportsRtl="true"

  3. Create following two methods in your MainActivity.java (wherever you want).

     public class MainActivity extends ActionBarActivity{
    
        .......
    
        // Implement OnclickListener for english_locale button
        findViewById(R.id.english_locale).setOnClickListener(new OnClickListener()
          {
    
             @Override
             public void onClick(View v)
             {
                 changeEnglish();
             }
          });
    
         // Implement OnclickListener for arabic_locale button
         findViewById(R.id.arabic_locale).setOnClickListener(new OnClickListener()
            {
    
               @Override
               public void onClick(View v)
                {
                   changeArabic();
                 }
            });
    
         /**
         * Method that Update UI for Arabic locale.
         */
         public void changeArabic() {
              new AsyncTask<Void, Void, Void>() {
    
              @Override
              protected Void doInBackground(Void... params) {
                   String app_locale = "ar";
                   Locale locale = new Locale(app_locale);
                   Locale.setDefault(locale);
    
                   //Configuration to query the current layout direction.
                   Configuration config = new Configuration();
                   config.locale = locale;
                   getResources().updateConfiguration(config,
                     getResources().getDisplayMetrics());
                   Bidi bidi = new Bidi(app_locale,
                     Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
                   bidi.isRightToLeft();
                   YourGlobalClass.updateLanguage(getActivity(), "ar");
    
                   //Refreshing current fragment
    
                   Intent i = getActivity().getIntent();
                   startActivity(i);
                   getActivity().finish();
                return null;
               }
    
            }.execute();
          }
    
             /**
             * Method that Update UI for Default(English) locale.
             */
           public void changeEnglish() {
    
               new AsyncTask<Void, Void, Void>() {
    
               @Override
               protected Void doInBackground(Void... params) {
                   String app_locale = "en";
                   Locale locale = new Locale(app_locale);
                   Locale.setDefault(locale);
    
                   //Configuration to query the current layout direction.
                   Configuration config = new Configuration();
                   config.locale = locale;
                   getResources().updateConfiguration(config,
                     getResources().getDisplayMetrics());
                   Bidi bidi = new Bidi(app_locale,
                     Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
                   bidi.isLeftToRight();
                   YourGlobalClass.updateLanguage(getActivity(), "en");
    
                   //Refreshing current fragment
                   Intent i = getActivity().getIntent();
                   startActivity(i);
                   getActivity().finish();
    
               return null;
               }
    
            }.execute();
          }
    
        ......
       //MainActivity end
     }
    

我无法在这些AsyncTasks中调用getActivity() - Ben Kane
使用以下代码刷新活动: Intent intent = getIntent(); finish(); startActivity(intent); - Silambarasan Poonguti
这个没起作用。我用你的代码强制将语言设置为阿拉伯语,但布局没有翻转。无论如何,我也不想这样做。我需要支持英语。有趣的是,在Bidi部分,布局方向仍然保持在0���即LTR。 - Ben Kane
我的意思是,在双向声明之后,bidi.isRightToLeft()返回的布尔值为false。 - Ben Kane
在您的活动的onCreate中尝试以下内容: getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL); - abhishesh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接