¿Cómo utilizo el enlace de datos para combinar una cadena de recursos con una variable dinámica en XML?

125

Tengo un TextView que tiene una cadena codificada y tengo una variable dinámica que quiero poner al final de esta cadena. Este es mi codigo:

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

Tengo un problema con android:text="@string/Generic_Text"+"@{ Profile.name }". Los Generic_Textestados "Mi nombre es" entonces Profile.namees dinámico y obviamente cambia de un perfil a otro. Lo quiero para que toda la salida de TextView sea Mi nombre es {Profile.name} . Cualquier ayuda sería genial.

Ignacio Perez
fuente
¿Está utilizando enlace de datos?
Malmling
Sí, estoy usando enlace de datos
Ignacio Perez
Agregue su código java actual también, por favor.
malmling

Respuestas:

162

Puedes hacerlo:

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

si usa formato de cadena para su Generic_Textcadena. ex. %sal final

C0D3LIC1OU5
fuente
Muchas gracias, acabo de poner eso y funcionó correctamente
Ignacio Perez
5
Esta no debería ser la respuesta aceptada, ya que en realidad no utiliza las funciones de enlaces de datos para manipular el texto.
Darwind
1
de acuerdo con @Darwind, vea mi respuesta para una implementación funcional con adaptadores de enlace
juanagui
@IgorGanapolsky esta respuesta tiene más de 3 años, pero definitivamente solía funcionar antes, ¿recuerdas qué salió mal cuando lo intentaste?
C0D3LIC1OU5
320

Puede hacer esto aún más simple:

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

tu cadena debería ser así:

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

Editar:

  1. Por supuesto, puede utilizar tantas variables como necesite:

    android:text= "@{@string/generic_text(profile.firstName, profile.secondName)}"
    
    <string name="generic_text">My Name is %1$s %2$s</string>
  2. Funciona solo porque está diseñado en enlace de datos. Más en documentos: https://developer.android.com/topic/libraries/data-binding/expressions#resources

Roman_D
fuente
1
pero muestra My Name is nullsi los datos aún no están listos (por ejemplo, no se cargaron desde la red)
user924
1
En este caso, compruébalo antes. android:text= "@{profile == null ? @string/loading : @string/generic_text(profile.firstName, profile.secondName)}"
Roman_D
¡Esto es útil!
akash89
La mejor respuesta :)
Heriberto Rivera
55

Muchas formas de concatizar cadenas

1. Uso de recurso de cadena ( recomendado debido a la localización )

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

Simplemente haga un recurso de cadena como este.

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

2. Concat codificado de forma rígida

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

Esto es útil cuando necesita un anexo codificado como + para el número de teléfono.

3. Usando Stringel método concat de '

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

Aquí spacehay una entidad html que se coloca dentro strings.xml. Porque XMLno acepta entidades Html ni caracteres especiales directamente. (Vincular entidades HTML)

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

4. Usando String.format()

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

tienes que importar la clase String en el diseño en este tipo.

<?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. Concat dos cadenas por recurso de cadena.

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

En este caso, ponga un recurso de cadena en strings.xml

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

Puede haber muchas otras formas, elija la que necesite.

Khemraj
fuente
5

Utilice un adaptador de encuadernación .

Esta muestra está escrita en Kotlin y tiene en cuenta que la variable vinculada puede ser nula:

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

luego use el adaptador de enlace en su XML en lugar de la android:textpropiedad

app:my_name="@{Profile.name}"
juanagui
fuente
He tenido muchos problemas para llamar a funciones importadas en el enlace, esta respuesta funciona perfectamente para mí y me permite reutilizar mis extensiones. ¡Gracias!
Danny Buonocore
Dado que la manipulación básica ya la proporciona la Stringclase de xml, esta solución solo es buena para ser utilizada para manipulaciones avanzadas de cadenas según sus requisitos. Sin embargo, no es incorrecto.
sud007
3

Actualización de 2019, Android Studio a 3.4, Android Gradle Plugin a 3.4

No es necesario importar más

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

para operaciones con cadenas. Por favor marque esta respuesta .

SANAT
fuente
1

En caso de que no pueda cambiar la cadena de recursos para que contenga %sal final (por ejemplo, porque se usa en otro lugar sin el sufijo):

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

Si Profile.nameno puede ser nulo, es suficiente. Sin embargo, si nullocurre, se bloqueará. Tienes que agregar otra capa:

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

(que requiere <import type="java.util.Objects"/>trabajar).

Nuevamente: todo este trabajo adicional vale la pena solo si tiene la cadena de recursos utilizada en otro lugar. La segunda razón es cuando desea manejar nullcomo "cadena vacía" en lugar de un literal "nulo".

Agent_L
fuente
2
Si el recurso de cadena se usa en otro lugar, ¿por qué no crear un nuevo recurso?
Jarett Millard
0

En caso de que desee escribir texto en XML, puede utilizar `` comillas.

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

en otro lugar necesita Concat con la Cadena o variable , puede usar

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

si desea Concat el recurso de cadena en lugar de la variable que puede hacer,

android:text="@{@string/app_name.concat(`Device Name`)}"
Merlín Jeyakumar
fuente
0

Solo usar el +operador funciona para mí:

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

String.xml será:

<string name="Generic_Text">Hello</string>
Shalu TD
fuente