58

我知道可以通过资源 id 在布局中引用资源:

android:text="@{@string/resourceName}"

但是,我想通过 id 引用资源,这仅在运行时才知道。作为一个简单的例子,假设我们有这样的模型:

public class MyPOJO {

    public final int resourceId = R.string.helloWorld;

}

现在我需要将此值用作格式字符串中的值。让我们称之为

<string name="myFormatString">Value is: %s</string>

最直接的方法不起作用:

android:text="@{@string/myFormatString(myPojo.resourceId)}"

这只会将整数值放入占位符(也证明我正确初始化了我的 POJO,所以我没有在这里提供整个布局)。

我也尝试过使用@BindingConversion,但它没有用(实际上是预期的,但我还是尝试了) -int仍然分配给占位符并且没有调用绑定方法。

如何通过 DataBinding 库中的 id 显式获取资源?

4

8 回答 8

31

另一种解决方案是为其创建自定义@BindingAdapter

@BindingAdapter({"format", "argId"})
public static void setFormattedText(TextView textView, String format, int argId){
    if(argId == 0) return;
    textView.setText(String.format(format, textView.getResources().getString(argId)));
}

然后单独提供变量。

<TextView
    app:format="@{@string/myFormatString}"
    app:argId="@{myPojo.resourceId}"

如果你需要多个参数,你可以使用一个数组,但在我的例子中,一个就足够了。

于 2015-10-16T16:14:12.423 回答
29

截至 2016 年 6 月,这在 XML 中是可能的:

android:text= "@{String.format(@string/my_format_string, myPojo.resourceId)}"
于 2016-06-27T08:45:07.903 回答
26

您可以使用:

android:text='@{(id > 0) ? context.getString(id) : ""}'
于 2017-09-13T23:30:23.907 回答
13

我最终创建了自己的方法:

public class BindingUtils {

    public static String string(int resourceId) {
        return MyApplication
                .getApplication()
                .getResources()
                .getString(resourceId);
    }

}

为其声明导入:

<data>

    <import type="com.example.BindingUtils" />

    ...

</data>

并在绑定期间调用它:

android:text="@{@string/myFormatString(BindingUtils.string(myPojo.resourceId))}"

有开箱即用的方法会很好。DataBinding 处于 Beta 版 - 所以也许它会在未来出现。

于 2015-08-28T16:16:54.870 回答
7

如果您已经Context在 xml 中定义了另一种解决方案,那么您将不需要导入String类。

android:text="@{@string/myFormatString(context.getString(pojo.res))}"

将为

<string name="myFormatString">Value is: %s</string>

如果您的 xml 中没有上下文。然后按照这个

<data>    
     <variable
         name="context"
         type="abc.UserActivity"/>

     <variable
         name="pojo"
         type="abc.MyPOJO"/>
 </data>

在你的Activity

ActivityUserBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
binding.setPojo(new MyPOJO());
binding.setContext(this);
于 2018-08-07T05:52:23.777 回答
3

您可以使用绑定适配器官方文档中描述的自动方法选择。以下描述来自该文档:

对于名为 的属性example,库会自动尝试查找setExample(arg)接受兼容类型作为参数的方法。不考虑属性的命名空间,仅在搜索方法时使用属性名称和类型。

例如,给定android:text="@{user.name}"表达式,库会查找setText(arg)接受由 . 返回的类型的方法user.getName()。如果返回类型user.getName()String,则库查找setText()接受String参数的方法。如果表达式返回 an int,则库将搜索setText()接受int参数的方法。表达式必须返回正确的类型,如有必要,您可以强制转换返回值。

考虑到这一点,您可以实现自己的绑定适配器,该适配器接受字符串资源的 ID 作为int参数。

@BindingAdapter("android:text")
fun setText(view: TextView, @StringRes resId: Int) {
    if (resId == 0) {
        view.text = null
    } else {
        view.setText(resId)
    }
}

这将允许您使用标准android:text属性通过其资源 ID 及其值来引用字符串。

<TextView
    android:id="@+id/text_view_id"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{myPojo.resourceId}" />
于 2021-03-22T20:50:09.970 回答
1

科特林版本:

@BindingAdapter("template", "resId")
fun TextView.setFormattedText(template: String, resId: Int) {
    if (template.isEmpty() || resId == 0) return
    text = template.format(resources.getString(resId))
}

在xml中

<TextView
    app:template="@{@string/myFormatString}"
    app:resId="@{viewModel.resourceId}"/>
于 2019-08-29T15:46:16.863 回答
1

您可以在 XML 中使用上下文

 <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text= "@{context.getString(myPojo.resourceId)}"
   />
于 2021-04-07T20:57:37.093 回答