如何防止在某些Android设备上将LTR布局强制转换为RTL?

时间:2019-01-27 21:29:49

标签: android android-layout right-to-left bidi

在我的应用中实现了RTL支持后,用户报告说LTR文本在阿拉伯语言环境中被强制为RTL。如下所示:

LTR text incorrectly forced as RTL

即使文本应左对齐,也请注意如何将其右对齐。

用户告诉我,此错误仅出现在

  • 华为Y5 Prime 2018版本8.1.0
  • 和LG G3版本6.0.0

在Samsung Galaxy J7 6.0.1版或带有SDK 23、26、27、28的Android仿真器上不存在。如该屏幕截图所示,它可以在RTL语言环境中正确呈现LTR。 :

LTR text displayed correctly in RTL locale

我无法在仿真器中重现它-LTR文本显示为左对齐,而RTL文本(在这种情况下为阿拉伯语)正确显示为右对齐。我怀疑根本原因是某些OEM已添加代码以在RTL语言环境中强制RTL布局。

请注意,由于我的应用程序是RSS feed阅读器,因此我无法控制所显示的实际文本,因此我不得不依靠Bidi算法(该算法可以正常工作!这些设备除外)。

我在清单中指定了android:supportsRtl="true"

<application
      android:allowBackup="true"
      android:name=".FeederApplication"
      android:icon="@mipmap/ic_launcher_round"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:label="@string/app_name"
      android:supportsRtl="true"
      android:usesCleartextTraffic="true"
      android:theme="@style/AppTheme">
...
</application>

link to full manifest

这是屏幕截图中的布局:

<com.nononsenseapps.feeder.views.ObservableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/scroll_view"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.nononsenseapps.feeder.ui.ReaderFragment">

  <!-- Action bar is overlayed, so add some padding -->
  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingStart="@dimen/keyline_1"
    android:paddingTop="?actionBarSize"
    android:paddingEnd="@dimen/keyline_1"
    android:paddingBottom="@dimen/activity_vertical_margin">


    <TextView
      android:id="@+id/story_title"
      style="@style/TextAppearance.Reader.Title"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginBottom="6dp"
      android:textDirection="anyRtl"
      android:textIsSelectable="true"
      android:transitionName="title"
      tools:text="@tools:sample/cities" />

    <TextView
      android:id="@+id/story_feedtitle"
      style="@style/TextAppearance.Reader.Author"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginTop="2dp"
      android:layout_marginBottom="2dp"
      android:textDirection="locale"
      android:textIsSelectable="true"
      tools:text="CowboyProgrammer" />

    <TextView
      android:id="@+id/story_author"
      style="@style/TextAppearance.Reader.Author"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginTop="2dp"
      android:layout_marginBottom="8dp"
      android:textDirection="locale"
      android:textIsSelectable="true"
      tools:text="Jonas, Sep 14 2015" />

    <com.nononsenseapps.feeder.views.LinkedTextView
      android:id="@+id/story_body"
      style="@style/TextAppearance.Reader.Body"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_marginTop="8dp"
      android:minHeight="300dp"
      android:textDirection="anyRtl"
      android:textIsSelectable="true"
      tools:text="@tools:sample/lorem/random" />
  </LinearLayout>


</com.nononsenseapps.feeder.views.ObservableScrollView>

如果您想知道ImageView在哪里-没有任何东西。您在屏幕快照中看到的图像作为ImageSpan内的LinkedTextView包含在内。

我使用anyRtl来获得混合文本的正确格式。如果默认行为(firstStrong)以英语单词开头,则它将以左对齐方式呈现文本。这是在TextViews上设置文本的代码:

val viewModel = getFeedItemViewModel(_id)
viewModel.liveItem.observe(this, androidx.lifecycle.Observer {
    rssItem = it

    rssItem?.let { rssItem ->
        setViewTitle()

        // feedDisplayTitle is a SpannableString
        mFeedTitleTextView.text = rssItem.feedDisplayTitle

        rssItem.pubDate.let { pubDate ->
            rssItem.author.let { author ->
                when {
                    author == null && pubDate != null ->
                        mAuthorTextView.text = getString(R.string.on_date,
                                pubDate.withZone(DateTimeZone.getDefault())
                                        .toString(dateTimeFormat))
                    author != null && pubDate != null ->
                        mAuthorTextView.text = getString(R.string.by_author_on_date,
                                // Must wrap author in unicode marks to ensure it formats
                                // correctly in RTL
                                unicodeWrap(author),
                                pubDate.withZone(DateTimeZone.getDefault())
                                        .toString(dateTimeFormat))
                    else -> mAuthorTextView.visibility = View.GONE
                }
            }
        }
    }
})

viewModel.liveImageText.observe(this, androidx.lifecycle.Observer {
    // the liveImageText is a SpannableString
    bodyTextView.text = it
})

// [...]

fun Fragment.unicodeWrap(text: String): String =
        BidiFormatter.getInstance(getLocale()).unicodeWrap(text)

fun Fragment.getLocale(): Locale? =
        context?.getLocale()

fun Context.unicodeWrap(text: String): String =
        BidiFormatter.getInstance(getLocale()).unicodeWrap(text)

fun Context.getLocale(): Locale =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            resources.configuration.locales[0]
        } else {
            @Suppress("DEPRECATION")
            resources.configuration.locale
        }

link to full file

正如我所说,我不控制文本的显示,我只是在显示(using this code)之前将(可能是HTML格式的)文本转换为SpannableString

那么,正如标题所述,是否有人知道为发生此错误的特定设备添加变通办法的方法?

1 个答案:

答案 0 :(得分:0)

在某些情况下,当用户绘制文本时,您的用户是否有使用RTL语言编写的应用程序,而该设备仅忽略了Bidi算法的响应?