Как использовать привязку данных для объединения строки из ресурсов с динамической переменной в XML?


125

У меня есть 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 был моим именем {Profile.name} . Любая помощь была бы замечательной.


Вы используете привязку данных?
Malmling

Да, я использую привязку данных
Игнасио Перес

Также добавьте свой текущий код Java.
Malmling

Ответы:


162

Ты можешь сделать это:

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

если вы используете строковое форматирование для своей Generic_Textстроки. ех. %sв конце


Большое спасибо, я просто вставил это, и он сработал правильно
Игнасио Перес

5
Это не должен быть принятым ответом, поскольку на самом деле он не использует функции привязки данных для управления текстом.
Darwind

1
согласен с @Darwind, пожалуйста, посмотрите мой ответ о работающей реализации с Binding Adapters
juanagui

@IgorGanapolsky, этому ответу более 3 лет, но он определенно работал раньше - вы помните, что пошло не так, когда вы его попробовали?
C0D3LIC1OU5

320

Вы можете сделать это еще проще:

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


1
но он показывает, My Name is nullесли данные еще не готовы (например, не были загружены из сети)
user924

1
В этом случае просто проверьте это раньше. android:text= "@{profile == null ? @string/loading : @string/generic_text(profile.firstName, profile.secondName)}"
Roman_D 03

Это полезно!
akash89

Лучший ответ :)
Эриберто Ривера

55

Множество способов объединения строк

1. Использование строкового ресурса ( рекомендуется из-за локализации )

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

Просто сделайте такой строковый ресурс.

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

2. Жестко запрограммированный concat

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

Это полезно, когда вам нужно жестко запрограммировать добавление типа + для номера телефона.

3. Использование Stringметода concat

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

Вот spacehtml-объект, который находится внутри strings.xml. Потому XMLчто не принимает объекты HTML или специальные символы напрямую. (Ссылка на HTML-объекты)

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

4. Использование String.format()

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

вам необходимо импортировать класс String в макет этого типа.

<?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>

Может быть много других способов, выберите тот, который вам нужен.


5

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

Этот пример написан на 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}"

У меня возникли проблемы с вызовом импортированных функций в привязке, этот ответ отлично работает для меня и позволяет повторно использовать мои расширения. Спасибо!
Дэнни Буонокоре,

Поскольку базовые манипуляции уже предоставляются Stringклассом from xml, это решение можно использовать только для расширенных манипуляций со строками в соответствии с вашими требованиями. Однако это не так.
sud007

3

Обновление 2019, Android Studio до 3.4, Android Gradle Plugin до 3.4

Больше не требуется импорт

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

для строковых операций. Пожалуйста, проверьте этот ответ .


1

В случае, если вы не можете изменить строку ресурса, чтобы она содержалась %sв конце (например, потому что она используется в другом месте без суффикса):

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

Если Profile.nameне может быть null, этого достаточно. Однако, если это nullпроизойдет, произойдет сбой. Вам нужно добавить еще один слой:

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

(что требует <import type="java.util.Objects"/>работы.)

Опять же: вся эта дополнительная работа стоит того, только если у вас есть строка ресурса, используемая в другом месте. Вторая причина - когда вы хотите обрабатывать nullкак «пустую строку», а не как «нулевой» литерал.


2
Если строковый ресурс используется где-то еще, почему бы просто не создать новый ресурс?
Джаретт Миллард

0

В случае, если вы хотите ввести текст в XML, вы можете использовать `` цитата.

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

в другом месте вам нужно Concat со строкой или переменной , вы можете использовать

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

если вы хотите использовать строковый ресурс Concat вместо переменной, которую вы можете сделать,

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

0

У +меня работает просто оператор:

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

String.xml будет:

<string name="Generic_Text">Hello</string>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.