How do I use databinding to combine a string from resources with a dynamic variable in XML?
Asked Answered
S

13

209

I have a TextView which has a hardcoded string and I have a dynamic variable that I want to put at the end of this string. This is my 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>

I am having an issue with android:text="@string/Generic_Text"+"@{ Profile.name }" . The Generic_Text states " My Name is " then the Profile.name is dynamic and obviously changes from profile to profile. I want it so that the whole TextView output is My Name is {Profile.name}. Any help would be great.

Sedation answered 16/8, 2016 at 15:10 Comment(3)
Are you using databinding?Mcglothlin
Yes I am using databindingSedation
Add your current java code as well please.Mcglothlin
A
236

You can do this:

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

if you use string formatting for your Generic_Text string. ex. %s at the end

Assuntaassur answered 16/8, 2016 at 15:29 Comment(5)
Thanks a lot I just put that in and it worked correctlySedation
This shouldn't be the accepted answer, as this actually doesn't use Data bindings features to manipulate the text.Aylesbury
agree with @Darwind, please see my answer for a working implementation with Binding AdaptersExegetic
@IgorGanapolsky this answer is over 3 years old but definitely used to work before - do you recall what went wrong when you tried it?Assuntaassur
Android studio does not offer intelisense with this. Is it normal or I have an issue with mine ?Briareus
S
433

You can do this even simplier:

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

you string should be like this:

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

Edit:

  1. Of course you can use as many variables as you need:

    android:text= "@{@string/generic_text(profile.firstName, profile.secondName)}"
    
    <string name="generic_text">My Name is %1$s %2$s</string>
    
  2. It works just because it's designed in data binding. More in docs: https://developer.android.com/topic/libraries/data-binding/expressions#resources

Shift answered 16/8, 2016 at 20:40 Comment(4)
but it shows My Name is null if data isn't ready yet (e.g. wasn't loaded from network)Thrower
In this case just check it before. android:text= "@{profile == null ? @string/loading : @string/generic_text(profile.firstName, profile.secondName)}"Shift
The best answer :)Aalborg
Android studio does not offer intelisense with this. Is it normal or I have an issue with mine ?Briareus
A
236

You can do this:

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

if you use string formatting for your Generic_Text string. ex. %s at the end

Assuntaassur answered 16/8, 2016 at 15:29 Comment(5)
Thanks a lot I just put that in and it worked correctlySedation
This shouldn't be the accepted answer, as this actually doesn't use Data bindings features to manipulate the text.Aylesbury
agree with @Darwind, please see my answer for a working implementation with Binding AdaptersExegetic
@IgorGanapolsky this answer is over 3 years old but definitely used to work before - do you recall what went wrong when you tried it?Assuntaassur
Android studio does not offer intelisense with this. Is it normal or I have an issue with mine ?Briareus
K
93

Many ways to concat strings

1. Using string resource (Recommended because Localization)

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

Just make string resource like this.

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

2. Hard coded concat

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

This is useful when you need hardcoded append like + for phone number.

3. Using String's concat method

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

Here space is an html entity which is placed inside strings.xml. Because XML does not accept Html entities or special characters directly. (Link Html Entities)

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

4. Using String.format()

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

you have to import String class in layout in this 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. concat two strings by string resource.

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

In this case put a string resource in strings.xml

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

There can be many other ways, choose one you need.

Known answered 1/8, 2018 at 18:51 Comment(1)
I get the error "cannot find identifiert format"Disloyalty
O
12

strings.xml: <string name="my_string">Hello %s</string>

view.xml: android:text="@{@string/my_string(name)}"

Obedient answered 13/7, 2021 at 11:36 Comment(1)
As supportive information, it requires data binding enabled in gradle and a layout tag as a root tag in the view.xml.Klausenburg
E
9

Use a Binding Adapter.

This sample is written in Kotlin and takes into account that the bound variable can be null:

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

then use the binding adapter in your XML instead of the android:text property

app:my_name="@{Profile.name}"
Exegetic answered 25/9, 2019 at 9:30 Comment(2)
Been having a lot of trouble calling imported functions in the binding, this answer works perfectly for me and allows me to reuse my extensions. Thanks!Gleeman
Since, basic manipulation is already provided by String class from xml, this solution is only good to be used for advanced String manipulations based on your requirements. However, it is not incorrect.Apelles
T
8

2019 Update, Android studio to 3.4, Android Gradle Plugin to 3.4

No more required to import

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

for string operations. Please check this answer.

Trilley answered 25/4, 2019 at 6:23 Comment(0)
I
7

In case if you want to type text in XML, you can use `` quotation.

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

elsewhere you need to Concat with the String or variable, you can use

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

if you want to Concat string resource instead of the variable you can do,

android:text="@{@string/app_name.concat(`Device Name`)}"
Infix answered 1/7, 2020 at 17:55 Comment(0)
R
5

You can also set string resource as parameter to other string resource using formatter like below:

<string name="first_param_text">Hello</string>
<string name="second_param_text">World</string>
<string name="formatted_text">%s lovely %s</string>

and

android:text="@{String.format(@string/formatted_text, @string/first_param_text, @string/second_param_text)}"

"Hello lovely World" will appear on the view.

Rader answered 1/12, 2020 at 9:41 Comment(0)
R
2

Just using + operator works for me:

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

String.xml will be:

<string name="Generic_Text">Hello</string>
Rivalry answered 24/7, 2020 at 13:37 Comment(0)
M
1

In case you can't change the resource string to contain %s at the end (eg. because it's used elsewhere without the suffix):

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

If Profile.name can't be null, that's enough. However, if a null happens, it'll crash. You have to add another layer:

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

(which requires <import type="java.util.Objects"/> to work.)

Again: all this extra work is worth it only if you have the resource string used elsewhere. The second reason is when you want to handle null as "empty string" instead of a "null" literal.

Meneau answered 22/6, 2018 at 15:54 Comment(1)
If the string resource is used elsewhere, why not just make a new resource?Cavalcade
B
1

if you search one way to set your text with DataBinding when you have a string.xml like that

strings.xml

<string name="your_string_name"><![CDATA[<b>Name: </b>%s]]</string>

this @BindingAdapter can help you

BindingAdapters.kt

@BindingAdapter("spannedText")
fun TextView.setSpannedTextAdapter(formated: String) {
    text = HtmlCompat.fromHtml(formated, HtmlCompat.FROM_HTML_MODE_LEGACY)
}

TextView atribute in your XML layout

app:spannedText="@{@string/your_string_name(`Hello World!`)}"

Output

Name: Hello World!

Boiled answered 19/5, 2023 at 13:24 Comment(0)
U
0

just put or append your string resource name it will work fine

e.x @string/test

android:text="@{@string/test+viewModel.name+@string/test}"

Unaccomplished answered 17/2, 2021 at 3:8 Comment(0)
L
0

yourViewBinding.yourTextView.setText(this.yourViewBinding.getRoot().getResources().getString(R.string.your_string) + yourStringVariable);

Lizzettelizzie answered 1/9, 2021 at 7:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.