DataBinding:如何通过动态ID获取资源?
DataBinding: How to get resource by dynamic id?
我知道可以通过资源 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 显式获取资源?
我最终创建了自己的方法:
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 阶段 - 所以也许将来会出现。
另一种解决方案是为其创建自定义 @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}"
如果需要多个参数,可以使用数组,但在我的情况下,一个就足够了。
截至 2016 年 6 月,这在 XML 中是可能的:
android:text= "@{String.format(@string/my_format_string, myPojo.resourceId)}"
您可以使用:
android:text='@{(id > 0) ? context.getString(id) : ""}'
另一种解决方案,如果您 已经在 xml 中定义了 Context
那么您将 不需要导入 String
class。
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);
Kotlin 版本:
@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}"/>
您可以使用绑定适配器官方文档中描述的automatic method selection。以下描述摘自该文档:
For an attribute named example
, the library automatically tries to find the method setExample(arg)
that accepts compatible types as the argument. The namespace of the attribute isn't considered, only the attribute name and type are used when searching for a method.
For example, given the android:text="@{user.name}"
expression, the library looks for a setText(arg)
method that accepts the type returned by user.getName()
. If the return type of user.getName()
is String
, the library looks for a setText()
method that accepts a String
argument. If the expression returns an int
instead, the library searches for a setText()
method that accepts an int
argument. The expression must return the correct type, you can cast the return value if necessary.
考虑到这一点,您可以实现自己的绑定适配器,它接受字符串资源的 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}" />
您可以在 XML
中使用上下文
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text= "@{context.getString(myPojo.resourceId)}"
/>
我知道可以通过资源 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 显式获取资源?
我最终创建了自己的方法:
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 阶段 - 所以也许将来会出现。
另一种解决方案是为其创建自定义 @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}"
如果需要多个参数,可以使用数组,但在我的情况下,一个就足够了。
截至 2016 年 6 月,这在 XML 中是可能的:
android:text= "@{String.format(@string/my_format_string, myPojo.resourceId)}"
您可以使用:
android:text='@{(id > 0) ? context.getString(id) : ""}'
另一种解决方案,如果您 已经在 xml 中定义了 Context
那么您将 不需要导入 String
class。
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);
Kotlin 版本:
@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}"/>
您可以使用绑定适配器官方文档中描述的automatic method selection。以下描述摘自该文档:
For an attribute named
example
, the library automatically tries to find the methodsetExample(arg)
that accepts compatible types as the argument. The namespace of the attribute isn't considered, only the attribute name and type are used when searching for a method.For example, given the
android:text="@{user.name}"
expression, the library looks for asetText(arg)
method that accepts the type returned byuser.getName()
. If the return type ofuser.getName()
isString
, the library looks for asetText()
method that accepts aString
argument. If the expression returns anint
instead, the library searches for asetText()
method that accepts anint
argument. The expression must return the correct type, you can cast the return value if necessary.
考虑到这一点,您可以实现自己的绑定适配器,它接受字符串资源的 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}" />
您可以在 XML
中使用上下文 <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text= "@{context.getString(myPojo.resourceId)}"
/>