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

2023-12-11

我试图在运行时更改应用程序的区域设置。它在 API 级别 24 以下的 Andorid 中工作正常。但在 API 级别 24 或更高版本中,布局方向不会根据区域设置而改变。 下面是在运行时更改区域设置的代码。我使用了 LocaleHelper 类,如下所示

public class LocaleHelper {

    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";

    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }

    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }

    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }

    public static Context setLocale(Context context, String language) {
        persist(context, language);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }

        return updateResourcesLegacy(context, language);
    }

    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }

    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();

        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Log.d("LocaleHelper", "language : "+language);
        Locale.setDefault(locale);

        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);
        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Resources resources = context.getResources();

        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        configuration.setLayoutDirection(locale);
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());

        return context;
    }
}

下面是我在活动类中使用的代码

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.titleTextView)
    TextView mTitleTextView;
    @BindView(R.id.descTextView)
    TextView mDescTextView;
    @BindView(R.id.aboutTextView)
    TextView mAboutTextView;
    @BindView(R.id.toTRButton)
    Button mToTRButton;
    @BindView(R.id.toENButton)
    Button mToENButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        setTitle(getString(R.string.main_activity_toolbar_title));
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
    }

    @OnClick(R.id.toTRButton)
    public void onChangeToTRClicked() {
        updateViews("ur");
    }

    @OnClick(R.id.toENButton)
    public void onChangeToENClicked() {
        updateViews("en");
    }

    private void updateViews(String languageCode) {
        Context context = LocaleHelper.setLocale(this, languageCode);
        Resources resources = context.getResources();

        mTitleTextView.setText(resources.getString(R.string.main_activity_title));
        mDescTextView.setText(resources.getString(R.string.main_activity_desc));
        mAboutTextView.setText(resources.getString(R.string.main_activity_about));
        mToTRButton.setText(resources.getString(R.string.main_activity_to_tr_button));
        mToENButton.setText(resources.getString(R.string.main_activity_to_en_button));

        setTitle(resources.getString(R.string.main_activity_toolbar_title));
        this.recreate();
    }
}

在我的应用程序类中,我添加了以下代码

@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
    }

现在,当我将语言环境从英语更改为乌尔都语时,语言会更改,但布局方向不会按预期更改。当我再次单击乌尔都语时,布局方向发生变化(第二次尝试)。以下是截图供参考

enter image description here

App language changes but layout direction does not changed

Now layout direction is RTL but it should be LTR for English language

请帮助解决问题


问题似乎是它没有反映第一次更新时布局方向的变化。我通过覆盖解决了这个问题onAttachedToWindow的方法Activity像下面这样:

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        getWindow().getDecorView().setLayoutDirection(
                "ur".equals(LocaleHelper.getLanguage(this)) ?
                View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
    }
}

在 API 25 上测试,运行良好。请小心,但目前我不确定这种方法是否有任何副作用。尽管如此,我认为这就是您正在寻找的。

我也会更新博客文章反映更优雅、更通用的代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

API 24 及更高版本中区域设置更改时出现 Android RTL 问题 的相关文章

  • Android - 在sqlite数据库中存储敏感数据

    我需要将敏感数据存储在 Android 应用程序的 sqlite 数据库中 我如何确定这些数据非常安全 我知道我可以使用密钥加密数据 但是我将该密钥存储在哪里 我也不想要求用户填写密钥 我只是希望它能够自行工作 因为我害怕逆向工程 所以我也
  • Android:写入握手字节失败(-1 / 14):管道损坏

    基本上我正在尝试使用添加后退功能 最小SDK设置为11 getActionBar setDisplayHomeAsUpEnabled true 这是我的功能 public class DetailActivity extends Actio
  • 找不到参数的方法 dependencyResolutionManagement()

    我正在尝试使用老师给我的一个项目 但它显示了一个错误 Settings file Users admin AndroidStudioProjects HTTPNetworking settings gradle line 1 A probl
  • React Native 从 JavaScript 代码内部访问 strings.xml

    有没有办法访问当前值android app src main res values strings xml从 JavaScript 代码内部 我想为每个构建放置不同的端点 URL 但我什至无法检测到反应本机代码内的构建类型 而不必求助于 D
  • SearchView过滤ListView

    我已经实现了搜索视图来过滤我的列表视图项目 当我输入任何文本时 它会过滤列表 但当我退出搜索视图时 它不会返回原始列表项 public class PlacesListAdapter extends ArrayAdapter
  • Android 30+ 中的视频捕获意图 - 只有所有者才能与待处理项目交互

    我正在尝试在我的应用程序上捕获视频 它可以在 android API 30 以下运行 但不能在 30 以上运行 似乎在 sdk 30 之后 android 不允许完全读取外部存储 作用域存储 我目前遇到这个错误 java lang Ille
  • 找不到 com.google.firebase:firebase-core:9.0.0 [重复]

    这个问题在这里已经有答案了 在遵循有些不一致的指示之后here https firebase google com docs admob android quick start name your project and here http
  • 是否可以将数组或对象添加到 Android 上的 SharedPreferences

    我有一个ArrayList具有名称和图标指针的对象 我想将其保存在SharedPreferences 我能怎么做 注意 我不想使用数据库 无论 API 级别如何 请检查SharedPreferences 中的字符串数组和对象数组 http
  • 计数物体和更好的填充孔的方法

    我是 OpenCV 新手 正在尝试计算物体的数量在图像中 我在使用 MATLAB 图像处理工具箱之前已经完成了此操作 并在 OpenCV Android 中也采用了相同的方法 第一步是将图像转换为灰度 然后对其进行阈值计算 然后计算斑点的数
  • 找不到处理意图 com.instagram.share.ADD_TO_STORY 的活动

    在我们的 React Native 应用程序中 我们试图让用户根据视图 组件中的选择直接将特定图像共享到提要或故事 当我们尝试直接使用 com instagram share ADD TO FEED 进行共享时 它以一致的方式完美运行 但是
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • Android SIP 来电使用带有广播接收器的服务

    大家好 其实我正在尝试创建一个应用程序 支持基于 SIP 通过互联网进行音频呼叫 这里使用本机 sip 我遇到了来电问题 我已经完成了服务的注册部分 但是在接听电话时我无法接听电话 请帮助我 Service file package exa
  • 是否有 ADB 命令来检查媒体是否正在播放

    我想使用 ADB 命令检查根植于终端的外部设备中是否正在播放音频 视频 我无法找到任何 ADB 命令 如果有 我尝试过 adb shell dumpsys media player 我想要一个命令来指定视频是否正在运行 您可以使用以下命令查
  • 在gradle插件中获取应用程序变体的包名称

    我正在构建一个 gradle 插件 为每个应用程序变体添加一个新任务 此新任务需要应用程序变体的包名称 这是我当前的代码 它停止使用最新版本的 android gradle 插件 private String getPackageName
  • 在 SQLite 中搜索时排除 HTML 标签和一些 UNICODE 字符

    更新 4 我已经成功运行了firstchar例如 但现在的问题是使用regex 即使包含头文件 它也无法识别regex操作员 有什么线索可以解决这个问题吗 更新 2 我已经编译了sqlite3我的项目中的库 我现在正在寻找任何人帮助我为我的
  • 如何发布Android .aar源以使Android Studio自动找到它们?

    我正在将库发布到内部 Sonatype Nexus 存储库 Android Studio 有一个功能 可以自动查找通过 gradle 引用的库的正确源 我将 aar 的源代码作为单独的 jar 发布到 Nexus 但 Android Stu
  • 如何使用InputConnectionWrapper?

    我有一个EditText 现在我想获取用户对此所做的所有更改EditText并在手动将它们插入之前使用它们EditText 我不希望用户直接更改中的文本EditText 这只能由我的代码完成 例如通过使用replace or setText
  • Android Studio 0.4.3 Eclipse项目没有gradle

    在此版本之前 在 Android Studio 中按原样打开 Eclipse 项目似乎很容易 无需任何转换 我更喜欢 Android Studio 环境 但我正在开发一个使用 eclipse 作为主要 IDE 的项目 我不想只为这个项目下载
  • Android访问远程SQL数据库

    我可以直接从 Android 程序访问远程 SQL 数据库 在网络服务器上 吗 即简单地打开包含所有必需参数的连接 然后执行 SQL 查询 这是一个私人程序 不对公众开放 仅在指定的手机上可用 因此我不担心第三方获得数据库访问权限 如果是这
  • Android Studio - Windows 7 上的 Android SDK 问题

    我对 Google i o 2013 上发布的最新开发工具 Android Studio 有疑问 我已经成功安装了该程序并且能够正常启动 我可以导入现有项目并对其进行编辑 但是 当我尝试单击 SDK 管理器图标或 AVD 管理器图标时 或者

随机推荐

  • CakePHP - 分页和排序二级关联

    我知道这个问题已经被问了 100 000 次 但我几乎阅读了所有 100 000 条回复 但似乎没有一个符合我的要求 我已经尝试了所有可能的组合 显然没有 但我担心我会在如此相对简单的事情上失败 这是我的第二个蛋糕项目 所以我绝不是专家 简
  • 如何绘制混合箱线图:一半箱线图,另一半有抖动点?

    我正在尝试制作与图 2d f 类似的图文章发表在 自然 杂志上今年 它基本上是一半箱线图 另一半是点 有人能给我一些提示吗 非常感谢 这些是我的数据和代码 它们生成了带有点的完整框 require magrittr require tidy
  • android 媒体播放器显示音频但不显示视频

    我正在使用媒体播放器来播放视频 它只播放音频而不播放视频 有人可以帮忙吗 我的代码如下 public class VideoViewApplication extends Application Override public void o
  • WHERE-CASE 子句子查询性能

    该问题可能特定于 SQL Server 当我编写如下查询时 SELECT FROM IndustryData WHERE Date 20131231 AND ReportTypeID CASE WHEN fnQuarterDate 2013
  • XSLT :将命名空间声明添加到根元素

    我有这个 XML 文档
  • 更新 SQL Server 2012 中的 varbinary(MAX) 字段丢失最后 4 位

    最近想做一些数据修补 尝试更新一列 typevarbinary 最大 更新值是这样的 0xFFD8F 6DC0676 但是 更新查询成功运行后 该值变为 0x0FFD8 6DC067 看起来最后 4 位丢失了 或者整个值右移了一个字节 我尝
  • 如何通过脚本设置Azure DevOps版本的描述?

    在 Azure DevOps 中 我尝试通过 PowerShell CMD 设置版本描述 以便根据构建步骤中工件的输入获得版本的动态描述 我尝试通过 powershell 设置发布变量 例如 Write Host vso task setv
  • 如何让循环中的多个ajax请求按顺序返回值?

    我必须循环发出一系列 Ajax 请求 大约有100个 每个请求都会返回一个 JSONP 变量 我从 JSON 中提取数据并将值附加到 div 中 问题是我希望 div 按函数调用的顺序附加数据 即依次 现在 每次刷新页面时 我都会根据请求完
  • Dask Dataframe 将列表的列拆分为多列

    在 Pandas 中可以轻松完成相同的任务 import pandas as pd df pd DataFrame lists i i 1 for i in range 10 df left right pd DataFrame x for
  • 这个“标签”在 C++ 中意味着什么?

    我正在阅读一些 C 代码 我看到了一些有趣的东西 代码是这样的 repeat code here fallback code here start another code 这是我第一次在 C 代码中看到这种 标签 我称之为标签是因为我在汇
  • 没有显式锁定的 postgres 死锁

    我使用 PostgreSQL 9 2 并且我没有在任何地方使用显式锁定 也没有LOCK声明也不SELECT FOR UPDATE 然而 最近我得到了ERROR 40P01 deadlock detected 不过 检测到死锁的查询被包装在事
  • 如何通过ajax将表单数据发送到python脚本?

    我正在努力处理 python 程序和 ajax 请求 我正在尝试将一些数据从 Javascript 获取到 python 程序中 我一直在使用 getfirst field name 的正常方法不起作用 我认为这是因为请求是通过 ajax
  • 在离开未保存更改的网页之前警告用户

    我的申请中有一些带有表格的页面 如何保护表单 以便在有人离开或关闭浏览器选项卡时 系统应提示他们确认是否确实要保留未保存数据的表单 简短 错误的答案 你可以通过以下方式做到这一点处理beforeunload事件并返回一个非空字符串 wind
  • iOS:UITableView 滚动太快时会混合数据

    我已经对 UITableViewCell 进行了子类化以向其添加自定义外观 在 MYTableViewCell 的初始化级别 我添加了 4 个子视图 UIImageView 和三个 UILabel 所有 4 个子视图都分配有不同的标签 在
  • Google 表格的活跃用户 VS 有效用户

    我正在编写一个简单的谷歌应用程序脚本应用程序 它根据请求页面的用户执行一些数据操作 根据谷歌文档对象 Session 有获取活动用户 and 获取有效用户 我目前使用它来确定用户 看一下代码 var email Session getAct
  • 操作栏下的进度栏

    问题摘要 我怎样才能做一个ProgressBar集成在内部ActionBar 就像在 Chrome 应用程序上一样 Details 看一下 Chrome 的截图 我想创建一个像这样的操作栏 在操作栏的正下方 有一个进度条 它根据页面加载情况
  • 具有可变宽度元素的 jquery 滑块

    是否可以创建一个 jquery 滑块 其中元素具有可变宽度 即并非所有元素都具有相同的宽度 如果是这样 我该怎么做 汉尼特 要设置 jQuery 滑块的宽度 只需使用 CSS 将其包装在 div 和样式中即可 您还可以通过 CSS 引用子元
  • 该解决方案可以安全地通过 webSoket 通信在网络上访问用户的私有证书吗?

    我们正在开发一个使用 https 协议 两种方式 的网页 我们需要访问用户的私有证书 因为我们需要通过用户的证书来签署文档 所以我们开发了一个通过Websoket与Web进行通信的Java应用程序 该应用程序将通过网络协议调用进行调用 与从
  • 检查同一列中是否有相似的字符串

    我有一个这样的数据框 df col1 col2 A the value is zero B this is a cat C the value is one D nothing is here E the colour is blue F
  • API 24 及更高版本中区域设置更改时出现 Android RTL 问题

    我试图在运行时更改应用程序的区域设置 它在 API 级别 24 以下的 Andorid 中工作正常 但在 API 级别 24 或更高版本中 布局方向不会根据区域设置而改变 下面是在运行时更改区域设置的代码 我使用了 LocaleHelper