Como uso a ligação de dados para combinar uma sequência de recursos com uma variável dinâmica em XML?

125

Eu tenho um TextView que possui uma string codificada e uma variável dinâmica que eu quero colocar no final dessa string. Este é o meu código:

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

Estou tendo um problema com android:text="@string/Generic_Text"+"@{ Profile.name }". Os Generic_Textestados "Meu nome é" então Profile.nameé dinâmico e obviamente muda de perfil para perfil. Quero que toda a saída do TextView seja My Name seja {Profile.name} . Qualquer ajuda seria ótimo.

Ignacio Perez
fonte
Você está usando ligação de dados?
malmling
Sim, eu estou usando ligação de dados
Ignacio Perez
Adicione seu código java atual também, por favor.
malmling

Respostas:

162

Você consegue fazer isso:

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

se você usar a formatação de sequência para sua Generic_Textsequência. ex. %sno fim

C0D3LIC1OU5
fonte
Muito obrigado Acabei de colocar isso em e funcionou corretamente
Ignacio Perez
5
Essa não deve ser a resposta aceita, pois na verdade não usa os recursos de vinculação de dados para manipular o texto.
Darwind
1
Concordo com @Darwind, consulte minha resposta para uma implementação de trabalho com adaptadores de Encadernação
juanagui
@IgorGanapolsky, esta resposta tem mais de 3 anos, mas definitivamente costumava funcionar antes - você se lembra do que deu errado quando tentou?
C0D3LIC1OU5
320

Você pode fazer isso ainda mais simples:

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

sua string deve ser assim:

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

Editar:

  1. Obviamente, você pode usar quantas variáveis ​​precisar:

    android:text= "@{@string/generic_text(profile.firstName, profile.secondName)}"
    
    <string name="generic_text">My Name is %1$s %2$s</string>
  2. Funciona apenas porque foi projetado na ligação de dados. Mais em documentos: https://developer.android.com/topic/libraries/data-binding/expressions#resources

Roman_D
fonte
1
mas mostra My Name is nullse os dados ainda não estão prontos (por exemplo, não foram carregados da rede)
user924
1
Nesse caso, basta verificar antes. android:text= "@{profile == null ? @string/loading : @string/generic_text(profile.firstName, profile.secondName)}"
Roman_D
Isso é útil!
Akash89 17/10/19
A melhor resposta :)
Heriberto Rivera
55

Muitas maneiras de concatenar strings

1. Usando o recurso de string ( recomendado porque localização )

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

Basta criar recursos de string como este.

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

2. Concat codificado

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

Isso é útil quando você precisa acrescentar código codificado como + para o número de telefone.

3. Usando Stringo método concat

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

Aqui spaceestá uma entidade html que é colocada dentro strings.xml. Porque XMLnão aceita entidades Html ou caracteres especiais diretamente. (Vincular entidades HTML)

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

4. Usando String.format()

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

você precisa importar a classe String no layout desse 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. concatize duas strings por recurso de string.

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

Nesse caso, coloque um recurso de string em strings.xml

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

Pode haver muitas outras maneiras, escolha uma que você precisa.

Khemraj
fonte
5

Use um adaptador de ligação .

Este exemplo é escrito em Kotlin e leva em consideração que a variável vinculada pode ser nula:

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

em seguida, use o adaptador de ligação em seu XML em vez da android:textpropriedade

app:my_name="@{Profile.name}"
juanagui
fonte
Tendo tido muitos problemas para chamar funções importadas na ligação, esta resposta funciona perfeitamente para mim e me permite reutilizar minhas extensões. Obrigado!
Danny Buonocore 20/03
Como a manipulação básica já é fornecida pela Stringclasse from xml, essa solução só é boa para ser usada em manipulações avançadas de String com base em seus requisitos. No entanto, não está incorreto.
sud007 26/04
3

Atualização de 2019, Android studio para 3.4, Android Gradle Plugin para 3.4

Não é mais necessário importar

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

para operações de string. Por favor, verifique esta resposta .

SANAT
fonte
1

Caso você não possa alterar a cadeia de recursos a conter %sno final (por exemplo, porque é usada em outro lugar sem o sufixo):

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

Se Profile.namenão puder ser nulo, basta. No entanto, se nullacontecer, ele travará. Você precisa adicionar outra camada:

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

(o que requer <import type="java.util.Objects"/>trabalho.)

Novamente: todo esse trabalho extra vale a pena apenas se você tiver a cadeia de recursos usada em outro lugar. O segundo motivo é quando você deseja manipular nullcomo "cadeia vazia" em vez de um literal "nulo".

Agent_L
fonte
2
Se o recurso de cadeia de caracteres for usado em outro lugar, por que não criar um novo recurso?
Jarett Millard
0

Caso deseje digitar texto em XML, use `` quote.

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

em qualquer outro lugar em que você precise Concat com a String ou a variável , você pode usar

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

se você quiser Concat o recurso de string em vez da variável que você pode fazer,

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

Apenas usar o +operador funciona para mim:

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

String.xml será:

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