Как предотвратить принудительное размещение LTR в RTL на некоторых устройствах Android? - PullRequest
0 голосов
/ 28 января 2019

После реализации поддержки RTL в моем приложении пользователь сообщил, что текст LTR принудительно переводится как RTL в арабских локалях.Это выглядит следующим образом:

LTR text incorrectly forced as RTL

Обратите внимание, как текст выровнен по правому краю, даже если он должен быть выровнен по левому краю.

Пользователь сказал мне, что эта ошибка присутствует только на

  • Huawei Y5 Prime 2018 версии 8.1.0
  • и LG G3 версии 6.0.0

это не присутствует на Samsung Galaxy J7 версии 6.0.1 или эмуляторе Android с SDK 23, 26, 27, 28. Там он корректно отображает LTR в локалях RTL, как показано на этом снимке экрана:

LTR text displayed correctly in RTL locale

Я не могу воспроизвести его в эмуляторе - там текст LTR отображается выровненным по левому краю, а текст RTL (в данном случае арабским) корректноотображается по правому краю.Я подозреваю, что основной причиной является то, что некоторые OEM-производители добавили код для принудительной компоновки RTL в локалях RTL.

Обратите внимание, что, поскольку мое приложение является средством чтения RSS-каналов, я не могу контролировать фактический отображаемый текст, поэтому яя вынужден полагаться на 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>

ссылка на полную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
        }

ссылка на полный файл

Как я уже сказал, я не контролирую текст дляЯ просто конвертирую (возможно, в формате HTML) текст в SpannableString перед отображением (, используя этот код ).

Итак, как говорится в заголовке, кто-нибудь знает оспособ добавить обходной путь для конкретных устройств, где эта ошибка возникает?

1 Ответ

0 голосов
/ 28 января 2019

Возможно ли, что у вашего пользователя есть приложение на языке RTL, и устройство просто пропускает ответ Bidi-алгоритма при построении текста в некоторых случаях?

...