Comment utiliser la liaison de données pour combiner une chaîne de ressources avec une variable dynamique en XML?

125

J'ai un TextView qui a une chaîne codée en dur et j'ai une variable dynamique que je veux mettre à la fin de cette chaîne. Voici mon code:

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

J'ai un problème avec android:text="@string/Generic_Text"+"@{ Profile.name }". Les Generic_Textétats "Mon nom est" alors le Profile.nameest dynamique et change évidemment de profil en profil. Je le veux pour que toute la sortie TextView soit Mon nom est {Profile.name} . Toute aide est la bienvenue.

Ignacio Perez
la source
Utilisez-vous la liaison de données?
malmling
Oui, j'utilise la liaison de données
Ignacio Perez
Ajoutez également votre code java actuel.
malmling

Réponses:

162

Tu peux le faire:

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

si vous utilisez une mise en forme de chaîne pour votre Generic_Textchaîne. ex. %sà la fin

C0D3LIC1OU5
la source
Merci beaucoup, je viens de le mettre et cela a fonctionné correctement
Ignacio Perez
5
Cela ne devrait pas être la réponse acceptée, car cela n'utilise en fait pas les fonctionnalités de liaisons de données pour manipuler le texte.
Darwind
1
d'accord avec @Darwind, s'il vous plaît voir ma réponse pour une implémentation fonctionnelle avec des adaptateurs de liaison
juanagui
@IgorGanapolsky cette réponse date de plus de 3 ans, mais elle fonctionnait certainement avant - vous souvenez-vous de ce qui n'a pas fonctionné lorsque vous l'avez essayé?
C0D3LIC1OU5
320

Vous pouvez le faire encore plus simplement:

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

votre chaîne devrait être comme ceci:

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

Éditer:

  1. Bien sûr, vous pouvez utiliser autant de variables que nécessaire:

    android:text= "@{@string/generic_text(profile.firstName, profile.secondName)}"
    
    <string name="generic_text">My Name is %1$s %2$s</string>
  2. Cela fonctionne simplement parce qu'il est conçu dans la liaison de données. Plus dans la documentation: https://developer.android.com/topic/libraries/data-binding/expressions#resources

Roman_D
la source
1
mais il montre My Name is nullsi les données ne sont pas encore prêtes (par exemple, n'ont pas été chargées à partir du réseau)
user924
1
Dans ce cas, vérifiez-le avant. android:text= "@{profile == null ? @string/loading : @string/generic_text(profile.firstName, profile.secondName)}"
Roman_D
Ceci est utile!
akash89
La meilleure réponse :)
Heriberto Rivera
55

De nombreuses façons de concaténer des chaînes

1. Utilisation de la ressource de chaîne ( recommandé parce que la localisation )

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

Créez simplement une chaîne de caractères comme celle-ci.

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

2. Concat codé en dur

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

Ceci est utile lorsque vous avez besoin d'un ajout codé en dur comme + pour le numéro de téléphone.

3. Utilisation de Stringla méthode concat de

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

Voici spaceune entité html qui est placée à l'intérieur strings.xml. Car XMLn'accepte pas directement les entités Html ou les caractères spéciaux. (Lier les entités HTML)

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

4. Utilisation String.format()

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

vous devez importer la classe String dans la mise en page dans ce type.

<?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. concattez deux chaînes par ressource de chaîne.

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

Dans ce cas, mettez une ressource chaîne dans strings.xml

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

Il peut y avoir de nombreuses autres façons, choisissez celle dont vous avez besoin.

Khemraj
la source
5

Utiliser un adaptateur de liaison .

Cet exemple est écrit en Kotlin et prend en compte le fait que la variable liée peut être nulle:

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

puis utilisez l'adaptateur de liaison dans votre XML au lieu de la android:textpropriété

app:my_name="@{Profile.name}"
Juanagui
la source
J'ai eu beaucoup de mal à appeler les fonctions importées dans la liaison, cette réponse fonctionne parfaitement pour moi et me permet de réutiliser mes extensions. Merci!
Danny Buonocore
Étant donné que la manipulation de base est déjà fournie par la Stringclasse de xml, cette solution ne peut être utilisée que pour les manipulations de chaînes avancées en fonction de vos besoins. Cependant, ce n'est pas incorrect.
sud007 le
3

Mise à jour 2019, Android Studio vers 3.4, Android Gradle Plugin vers 3.4

Plus besoin d'importer

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

pour les opérations de chaîne. Veuillez vérifier cette réponse .

SANAT
la source
1

Dans le cas où vous ne pouvez pas modifier la chaîne de ressources pour qu'elle contienne %sà la fin (par exemple parce qu'elle est utilisée ailleurs sans le suffixe):

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

Si Profile.namene peut pas être nul, cela suffit. Cependant, si un nullse produit, il plantera. Vous devez ajouter un autre calque:

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

(ce qui nécessite <import type="java.util.Objects"/>de travailler.)

Encore une fois: tout ce travail supplémentaire ne vaut la peine que si vous avez la chaîne de ressources utilisée ailleurs. La deuxième raison est lorsque vous souhaitez traiter nullcomme "chaîne vide" au lieu d'un littéral "nul".

Agent_L
la source
2
Si la ressource chaîne est utilisée ailleurs, pourquoi ne pas simplement créer une nouvelle ressource?
Jarett Millard
0

Si vous souhaitez taper du texte en XML, vous pouvez utiliser `` quotation.

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

ailleurs, vous devez concaténer avec la chaîne ou la variable , vous pouvez utiliser

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

si vous souhaitez concaténer la ressource de chaîne au lieu de la variable que vous pouvez faire,

android:text="@{@string/app_name.concat(`Device Name`)}"
Merlin Jeyakumar
la source
0

Le simple fait d'utiliser un +opérateur fonctionne pour moi:

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

String.xml sera:

<string name="Generic_Text">Hello</string>
Shalu TD
la source