如何使用数据绑定将资源中的字符串与 XML 中的动态变量组合起来?

How do I use databinding to combine a string from resources with a dynamic variable in XML?

我有一个 TextView,它有一个硬编码的字符串,我有一个动态变量,我想把它放在这个字符串的末尾。这是我的代码:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp">
    <TextView
        android:id="@+id/PeopleName"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/Generic_Text"+"@{ Profile.name }" />


</LinearLayout>

我遇到了 android:text="@string/Generic_Text"+"@{ Profile.name }" 的问题。 Generic_Text 声明“我的名字是”,然后 Profile.name 是动态的,并且显然会随着配置文件的不同而变化。我想要这样整个 TextView 输出是 My Name is {Profile.name}。任何帮助都会很棒。

你可以这样做:

android:text= "@{String.format(@string/Generic_Text, Profile.name)}"

如果您对 Generic_Text 字符串使用字符串格式。前任。 %s最后

您可以更简单地执行此操作:

android:text= "@{@string/generic_text(profile.name)}"

你的字符串应该是这样的:

<string name="generic_text">My Name is %s</string>

编辑:

  1. 当然你可以根据需要使用任意多个变量:

    android:text= "@{@string/generic_text(profile.firstName, profile.secondName)}"
    
    <string name="generic_text">My Name is %1$s %2$s</string>
    
  2. 之所以有效,是因为它是在数据绑定中设计的。更多文档:https://developer.android.com/topic/libraries/data-binding/expressions#resources

如果您不能更改资源字符串以在末尾包含%s(例如,因为它在没有后缀的其他地方使用):

android:text="@{@string/Generic_Text.concat(Profile.name)}"

如果Profile.name不能为空,那就够了。但是,如果 null 发生,它就会崩溃。您必须添加另一层:

android:text="@{@string/Generic_Text.concat(Objects.toString(Profile.name))}"

(需要 <import type="java.util.Objects"/> 才能工作。)

再说一次:只有在别处使用资源字符串时,所有这些额外的工作才值得。第二个原因是当您想将 null 作为 "empty string" 而不是 "null" 文字处理时。

连接字符串的多种方法

1。使用字符串资源(推荐,因为本地化

android:text= "@{@string/generic_name(user.name)}"

像这样制作字符串资源。

<string name="generic_name">Hello %s</string>

2。硬编码连接

android:text="@{`Hello ` + user.name}"/>

当您需要像 + 这样的硬编码附加到 phone 数字时,这很有用。

3。使用 String 的连接方法

android:text="@{user.firstName.concat(@string/space).concat(user.lastName)}"

这里 space 是一个 html 实体,它被放置在 strings.xml 中。因为 XML 不直接接受 Html 实体或特殊字符。

<string name="space">\u0020</string>

4。使用 String.format()

android:text= "@{String.format(@string/Hello, user.name)}"

你必须在这种类型的布局中导入字符串 class。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="String" />
    </data>
    <TextView
        android:text= "@{String.format(@string/Hello, user.name)}"
        ... >
    </TextView>
</layout>

5。通过字符串资源连接两个字符串。

android:text="@{@string/generic_name(user.firstName,user.lastName)}"

在这种情况下,将字符串资源放入 strings.xml

<string name="generic_name">%1$s, %2$s</string>

还有很多方法,选择你需要的一种。

2019 更新,Android studio 到 3.4,Android Gradle 插件到 3.4

不再需要导入

<import type="java.lang.String" />" 

用于字符串操作。请检查此 .

使用 Binding Adapter.

此示例是用 Kotlin 编写的,并考虑到绑定变量可以为 null:

@BindingAdapter("my_name")
fun TextView.setMyName(name: String?) {
    this.text =
        if (name.isNullOrEmpty()) "" else "${this.context.getString(R.string.Generic_Text)} $name"
}

然后在您的 XML 中使用绑定适配器而不是 android:text 属性

app:my_name="@{Profile.name}"

如果您想在 XML 中 键入文本 ,您可以使用 `` 引号。

android:text="@{`Device Name`}"

在其他地方你需要连接字符串或变量,你可以使用

android:text="@{`Device Name`.concat(android.os.Build.MANUFACTURER)}"

如果你想连接字符串资源而不是你可以做的变量,

android:text="@{@string/app_name.concat(`Device Name`)}"

仅使用 + 运算符对我有用:

android:text= "@{@string/Generic_Text +' '+ Profile.name)}"

String.xml 将是:

<string name="Generic_Text">Hello</string>

您还可以使用格式化程序将字符串资源设置为其他字符串资源的参数,如下所示:

<string name="first_param_text">Hello</string>
<string name="second_param_text">World</string>
<string name="formatted_text">%s lovely %s</string>

android:text="@{String.format(@string/formatted_text, @string/first_param_text, @string/second_param_text)}"

“Hello lovely World”将出现在视图中。

只需输入或附加您的字符串资源名称即可正常工作

e.x@string/test

android:text="@{@string/test+viewModel.name+@string/test}"

strings.xml: <string name="my_string">Hello %s</string>

view.xml: android:text="@{@string/my_string(name)}"

yourViewBinding.yourTextView.setText(this.yourViewBinding.getRoot().getResources().getString(R.string.your_string) + yourStringVariable);