我们如何使用数据绑定从字符串资源中获取SpannedString对象?

时间:2018-11-01 18:07:56

标签: android android-resources android-databinding

Florina Muntenescu撰写了a cool post,内容涉及在字符串资源中使用<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参数类型使用CharSequencethingy,它将生成,但是随后我通过了String,并且注释范围从字符串资源。

那么,我该怎么办?

  • 获取与我的字符串资源相对应的SpannedString(即您从getText()而不是getString()获得的信息),或
  • 获取我的字符串资源的字符串资源ID,以便我自己打电话给getText()以获取我的SpannedString

4 个答案:

答案 0 :(得分:4)

作为表达式,@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"/>

答案 1 :(得分:3)

这也许是一种不太邪恶的方式:

定义带注释的字符串。

<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);
}

尽管有些牵连,但这还是可行的。如果有多个字符串,则可以扩展数组。

答案 2 :(得分:0)

使用此绑定适配器:

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

,而不是使用app:thingy="@{@string/my_annotated_string}",而是将资源传递到绑定中:thingy="@string/my_annotated_string"(没有app:)。

答案 3 :(得分:0)

一个人可以使用<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缺少绑定它所需的getter,也没有一个可以向框架类中添加注释。