Як я можу використовувати прив'язку даних для об'єднання рядка з ресурсів з динамічною змінною в 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} . Будь-яка допомога була б чудовою.


Чи використовуєте ви прив'язку даних?
марення

Так, я використовую прив'язку даних
Ігнасіо Перес

Додайте також свій поточний код Java.
марення

Відповіді:


162

Ви можете зробити це:

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

якщо ви використовуєте для форматування Generic_Textрядків рядки. колишній %sв кінці


Велике спасибі, я просто поставив це, і він працював правильно
Ігнасіо Перес

5
Це не повинно бути прийнятою відповіддю, оскільки це фактично не використовує функції прив'язки даних для маніпулювання текстом.
Дарвінд

1
згоден з @Darwind, дивіться мою відповідь про робочу реалізацію за допомогою адаптерів зв’язування
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

Це корисно!
akash89

Найкраща відповідь :)
Херіберто Рівера

55

Багато способів конфатувати рядків

1. Використання рядкового ресурсу ( рекомендується через локалізацію )

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

Просто зробіть рядовий ресурс таким.

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

2. Жорстко закодований конмат

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

Використовуйте адаптер зв’язування .

Цей зразок написаний у Котліні та враховує, що зв'язана змінна може бути нульовою:

@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}"

У мене виникли багато проблем з викликом імпортованих функцій у прив'язці, ця відповідь для мене прекрасно працює і дозволяє повторно використовувати мої розширення. Дякую!
Danny Buonocore

Оскільки основні маніпуляції вже надані Stringкласом з xml, це рішення добре використовувати лише для розширених маніпуляцій String, виходячи з ваших вимог. Однак це невірно.
sud007

3

Оновлення 2019 року, Android-студія до 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станеться, воно зазнає краху. Ви повинні додати ще один шар:

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

(що вимагає <import type="java.util.Objects"/>роботи.)

Знову ж таки: вся ця додаткова робота варта того лише, якщо у вас є рядок ресурсів, що використовується в іншому місці. Друга причина - коли ви хочете обробити nullяк "порожній рядок" замість "нульового" літералу.


2
Якщо рядовий ресурс використовується в іншому місці, чому б просто не створити новий ресурс?
Джаретт Міллард

0

У випадку, якщо ви хочете ввести текст у XML, ви можете використати цитату `` .

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

в іншому місці, де потрібно скористатися рядком або змінною , ви можете використовувати

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.