Как мы получаем объекты SpannedString из строковых ресурсов, используя привязку данных? - PullRequest
0 голосов
/ 01 ноября 2018

Флорина Мунтенеску написала классный пост об использовании <annotation> в строковых ресурсах для обеспечения гибкой разметки, которую вы можете обрабатывать в своем приложении с помощью пользовательских диапазонов. Я пытаюсь использовать его в привязке данных, но не могу понять, как получить SpannedString строковый ресурс из привязки данных.

В моем макете у меня есть app:thingy="@{@string/my_annotated_string}" как атрибут на TextView. У меня есть адаптер привязки, настроенный для обработки thingy атрибутов. Тем не менее, система привязки данных, кажется, настаивает на том, что мое значение равно String.

Я пытался:

@BindingAdapter("thingy")
@JvmStatic
fun handleThingy(textView: TextView, thingy: SpannedString) { /* stuff goes here */ }

и

@BindingAdapter("thingy")
@JvmStatic
fun handleThingy(textView: TextView, thingy: Spanned) { /* stuff goes here */ }

и

@BindingAdapter("thingy")
@JvmStatic
fun handleThingy(textView: TextView, @StringRes thingy: Int) { /* stuff goes here */ }

Во всех случаях я получаю Cannot find the setter for attribute 'app:thingy' with parameter type java.lang.String on android.widget.TextView ошибок сборки.

Если я использую String или CharSequence для типа параметра thingy, он строится, но затем я получаю String, и у меня нет интервалов аннотации из строкового ресурса.

Итак, как я могу:

  • Получите SpannedString, соответствующий моему строковому ресурсу (то есть, что вы получите от getText() вместо getString()) или
  • Получите идентификатор строкового ресурса моего строкового ресурса, чтобы я мог сам вызвать getText(), чтобы получить SpannedString

Ответы [ 4 ]

0 голосов
/ 10 ноября 2018

можно определить любой тип данных с помощью <import>:

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List<String>"/>
    <variable name="sparse" type="SparseArray<String>"/>
    <variable name="map" type="Map<String, String>"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>

и получите из него текст:

android:text="@{sparse[index]}"

для определения thingy с типом данных SpannedString (или с типом extends SpannedString):

<data>
    <import type="com.acme.model.BindableSpannedString"/>
    <variable name="thingy" type="BindableSpannedString"/>
    <variable name="index" type="int"/>
</data>

геттер, помеченный @Bindable, должен иметь индексный доступ:

android:text="@{thingy.getSpanAt(index)}"

SpannedString не хватает геттера, необходимого для его привязки, и нельзя добавлять аннотации к классам каркаса.

0 голосов
/ 05 ноября 2018

Вот, пожалуй, немного менее изворотливый способ:

Определить аннотированную строку.

<string name="my_annotated_string">A <annotation font="title_emphasis">cool</annotation> annotation <annotation font="title_emphasis">thingy</annotation>.</string>

Поместите ссылку на этот строковый ресурс в TypedArray:

<resources>
    <array name="annotated_text">
        <item>@string/my_annotated_string</item>
    </array>
</resources>

Ссылка на TypedArray в макете:

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:thingy="@{@typedArray/annotated_text}" />

Наконец, установите BindingAdapter, чтобы захватить SpannedString с аннотациями:

@BindingAdapter("thingy")
public static void setThingy(TextView textView, TypedArray strings) {
    SpannedString ss = (SpannedString) strings.getText(0);
    Object spans[] = ss.getSpans(0, ss.length(), Object.class);
}

Хотя это немного связано, это работает. Если есть несколько строк, массив может быть расширен.

0 голосов
/ 08 ноября 2018

Используйте этот адаптер для привязки:

@BindingAdapter("thingy")
fun handleThingy(textView: TextView, @StringRes thingy: Int) { /* stuff goes here */ }

и вместо использования app:thingy="@{@string/my_annotated_string}" передать ресурс в привязку: thingy="@string/my_annotated_string" (без app:).

0 голосов
/ 05 ноября 2018

В качестве выражения @string/my_annotated_string вычисляется как строка. Несмотря на то, что это напоминает ссылку на строковый ресурс в XML, на самом деле это всего лишь значение String.

Было бы неплохо также иметь версию @text/my_annotated_string, но по состоянию на данный момент она недоступна.

Вместо этого вам придется использовать фактический ресурс в выражении привязки:

app:thingy="@{string.my_annotated_string}"
app:thingy="@{context.getText(string.my_annotated_string)}"

Это предполагает импорт класса string:

<import type="path.to.R.string"/>
...