Jak używać wiązania danych, aby połączyć ciąg z zasobów ze zmienną dynamiczną w formacie XML?

125

Mam TextView, który ma zakodowany ciąg i mam dynamiczną zmienną, którą chcę umieścić na końcu tego ciągu. To jest mój kod:

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

Mam problem z android:text="@string/Generic_Text"+"@{ Profile.name }". Stan Generic_Text„Moje imię to” jest wtedy Profile.namedynamiczny i oczywiście zmienia się w zależności od profilu. Chcę, żeby całe wyjście TextView miało na imię My Name to {Profile.name} . Każda pomoc byłaby świetna.

Ignacio Perez
źródło
Czy używasz wiązania danych?
malmling
Tak, używam wiązania danych
Ignacio Perez
Dodaj również swój aktualny kod java.
malmling

Odpowiedzi:

162

Możesz to zrobić:

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

jeśli używasz formatowania ciągu dla swojego Generic_Textciągu. dawny. %sna końcu

C0D3LIC1OU5
źródło
Wielkie dzięki, po prostu włożyłem to i zadziałało poprawnie
Ignacio Perez
5
Nie powinna to być akceptowana odpowiedź, ponieważ w rzeczywistości nie wykorzystuje ona funkcji powiązań danych do manipulowania tekstem.
Darwind
1
zgadzam się z @Darwind, zobacz moją odpowiedź na działającą implementację z Binding Adapters
juanagui
@IgorGanapolsky ta odpowiedź ma ponad 3 lata, ale na pewno działała wcześniej - czy pamiętasz, co poszło nie tak, kiedy ją wypróbowałeś?
C0D3LIC1OU5
320

Możesz to zrobić jeszcze prościej:

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

Twój ciąg powinien wyglądać tak:

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

Edytować:

  1. Oczywiście możesz użyć tylu zmiennych, ile potrzebujesz:

    android:text= "@{@string/generic_text(profile.firstName, profile.secondName)}"
    
    <string name="generic_text">My Name is %1$s %2$s</string>
  2. Działa tylko dlatego, że jest zaprojektowany w powiązaniu danych. Więcej w dokumentach: https://developer.android.com/topic/libraries/data-binding/expressions#resources

Roman_D
źródło
1
ale pokazuje, My Name is nullczy dane nie są jeszcze gotowe (np. nie zostały załadowane z sieci)
user924
1
W takim przypadku po prostu sprawdź to wcześniej. android:text= "@{profile == null ? @string/loading : @string/generic_text(profile.firstName, profile.secondName)}"
Roman_D
To jest pomocne!
akash89
Najlepsza odpowiedź :)
Heriberto Rivera
55

Wiele sposobów łączenia ciągów

1. Korzystanie z zasobu ciągu ( zalecane ze względu na lokalizację )

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

Po prostu utwórz zasób ciągów w ten sposób.

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

2. Concat zakodowany na stałe

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

Jest to przydatne, gdy potrzebujesz wpisanego na stałe kodu, takiego jak + dla numeru telefonu.

3. Korzystanie Stringz metody concat

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

Oto spacejednostka HTML, która jest umieszczona wewnątrz strings.xml. Ponieważ XMLnie akceptuje bezpośrednio jednostek HTML ani znaków specjalnych. (Połącz jednostki HTML)

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

4. Korzystanie String.format()

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

musisz zaimportować klasę String w układzie tego typu.

<?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. połącz dwa ciągi według zasobu ciągu.

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

W tym przypadku wstaw zasób ciągu strings.xml

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

Istnieje wiele innych sposobów, wybierz ten, którego potrzebujesz.

Khemraj
źródło
5

Użyj łącznika do wiązania .

Ten przykład jest napisany w Kotlinie i bierze pod uwagę, że zmienna związana może mieć wartość null:

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

następnie użyj adaptera powiązania w kodzie XML zamiast android:textwłaściwości

app:my_name="@{Profile.name}"
juanagui
źródło
Miałem wiele problemów z wywołaniem funkcji importowanych w powiązaniu, ta odpowiedź działa idealnie dla mnie i pozwala mi ponownie użyć moich rozszerzeń. Dzięki!
Danny Buonocore
Ponieważ podstawowa manipulacja jest już zapewniana przez Stringklasę from xml, to rozwiązanie nadaje się tylko do zaawansowanych operacji na ciągach znaków w oparciu o twoje wymagania. Jednak nie jest to błędne.
sud007
3

Aktualizacja 2019, Android studio do wersji 3.4, wtyczka Android Gradle do wersji 3.4

Nie trzeba już importować

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

do operacji na strunach. Proszę sprawdzić tę odpowiedź .

SANAT
źródło
1

W przypadku, gdy nie możesz zmienić ciągu zasobu tak, aby zawierał %sna końcu (np. Ponieważ jest używany w innym miejscu bez sufiksu):

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

Jeśli Profile.namenie może być zerowe, to wystarczy. Jednak jeśli nulltak się stanie, ulegnie awarii. Musisz dodać kolejną warstwę:

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

(co wymaga <import type="java.util.Objects"/>pracy.)

Ponownie: cała ta dodatkowa praca jest tego warta tylko wtedy, gdy masz ciąg zasobów używany w innym miejscu. Drugim powodem jest sytuacja, w której chcesz traktować nulljako „pusty łańcuch” zamiast literału „null”.

Agent_L
źródło
2
Jeśli zasób string jest używany gdzie indziej, dlaczego nie utworzyć po prostu nowego zasobu?
Jarett Millard
0

W przypadku, gdy chcesz wpisać tekst w XML, możesz użyć `` cudzysłowu.

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

gdzie indziej musisz Concat z Stringiem lub zmienną , możesz użyć

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

jeśli chcesz połączyć zasób łańcuchowy zamiast zmiennej, którą możesz zrobić,

android:text="@{@string/app_name.concat(`Device Name`)}"
Merlin Jeyakumar
źródło
0

Samo użycie +operatora działa dla mnie:

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

String.xml będzie:

<string name="Generic_Text">Hello</string>
Shalu TD
źródło