Android Data Binding using include tag

94,549

Solution 1

The problem is that the included layout isn't being thought of as a data-bound layout. To make it act as one, you need to pass a variable:

buttons.xml:

<layout xmlns:andr...>
  <data>
    <variable name="foo" type="int"/>
  </data>
  <Button
    android:id="@+id/button"
    ...." />

main.xml:

<layout xmlns:andr...
...
   <include layout="@layout/buttons"
            android:id="@+id/buttons"
            app:foo="@{1}"/>
....

Then you can access buttons indirectly through the buttons field:

MainBinding binding = MainBinding.inflate(getLayoutInflater());
binding.buttons.button

As of 1.0-rc4 (just released), you no longer need the variable. You can simplify it to:

buttons.xml:

<layout xmlns:andr...>
  <Button
    android:id="@+id/button"
    ...." />

main.xml:

<layout xmlns:andr...
...
   <include layout="@layout/buttons"
            android:id="@+id/buttons"/>
....

Solution 2

Easy Complete Example

Just set id to included layout, and use binding.includedLayout.anyView.

This example helps passing a value to <include & accessing included views in code.

Step 1

You have layout_common.xml, want to pass String to included layout.

You will create String variable in layout and refer this String to TextView.

<data>
    // declare fields
    <variable
        name="passedText"
        type="String"/>
</data>

<TextView
    android:id="@+id/textView"
    ...
    android:text="@{passedText}"/> //set field to your view.

Step 2

Include this layout to parent layout. Give an id to included layout, so that we can use that in binding class. Now you can pass String passedText to your <include tag.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        ..
        >

        <include
            android:id="@+id/includedLayout"
            layout="@layout/layout_common"
            app:passedText="@{@string/app_name}" // here we pass any String 
            />

    </LinearLayout>
</layout>
  • You can use now binding.includedLayout.textView in your class.
  • You can pass any variables to included layout like above.

    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    binding.includedLayout.textView.setText("text");
    

Note Both layouts (parent & included) should be binding layout, wrapped with <layout

Solution 3

just set an id for your include layout

    <include
        android:id="@+id/layout"
        layout="@layout/buttons" />

then

BUTTONSBINDING binding = yourMainBinding.layout;

BUTTONSBINDING is res/layout/buttons.xml

now :

binding.button.setText("simple_Way");

Solution 4

You can make your bind work on your include just adding a ID to it like so:

<include
            android:id="@+id/loading"
            layout="@layout/loading_layout"
            bind:booleanVisibility="@{viewModel.showLoading}" />

Solution 5

An other interesting thing on this is that you can pas variables to the imported layout from the binder like this:

MainBinding binding = MainBinding.inflate(getLayoutInflater());
binding.buttons.setVariable(BR.varID, variable)
Share:
94,549

Related videos on Youtube

Kamil Nękanowicz
Author by

Kamil Nękanowicz

Java, Spring, Android!

Updated on January 18, 2022

Comments

  • Kamil Nękanowicz
    Kamil Nękanowicz over 2 years

    Update note:

    The above example works properly, because release 1.0-rc4 fixed the issue of needing the unnecessary variable.

    Original question:

    I do exactly as it is described in the documentation and it does not work:

    main.xml:

    <layout xmlns:andr...
        <data>
        </data>
           <include layout="@layout/buttons"></include>
    ....
    

    buttons.xml:

    <layout xmlns:andr...>
        <data>
        </data>
        <Button
            android:id="@+id/button"
            ...." />
    

    MyActivity.java:

     ... binding = DataBindingUtil.inflate...
    binding.button; ->cannot resolve symbol 'button'
    

    how to get button?

  • George Mount
    George Mount over 8 years
    1.0-rc4 now fixes the problem of needing the unnecessary variable. You can now use simply: <include layout="@layout/buttons" android:id="@+id/buttons"/>. You still need the id so that it will produce a public field for you so that you can access the Button View.
  • Nilzor
    Nilzor over 8 years
    Are anyone else having problems binding click events on the layout though?
  • George Mount
    George Mount over 8 years
    Are you using data binding syntax? android:onClick="@{myObj.clickHandler}"
  • Sowmia Sundararajan
    Sowmia Sundararajan almost 8 years
    Databinding with include support. developer.android.com/topic/libraries/data-binding/…
  • Rishabh876
    Rishabh876 over 6 years
    Main point to remember here is to get the button reference, you need to do binding.{id of include tag}.button instead of binding.button. Took me a while to figure it out.
  • Khemraj Sharma
    Khemraj Sharma almost 6 years
    @GeorgeMount How to call static method from layout element like android:text="{MyClass.getUser().name}" ?
  • George Mount
    George Mount almost 6 years
    You can do that either by importing the class name using the <import type="com.example.MyClass"/> in the data section or by using the fully qualified class name in the expression: android:text="@{com.example.MyClass.user.name}"
  • CodingTT
    CodingTT over 5 years
    what if you want to pass in two parameters/
  • George Mount
    George Mount over 5 years
    If you want to pass two parameters, you can just do that. <include layout="..." app:param1="@{1}" app:param2="@{2}"/> where param1 and param2 are variables in your included layout.
  • Neon Warge
    Neon Warge over 5 years
    Apologies, would you care to type the entire layout? This '...' all over the place is pretty much unreadable. Like I don't understand if I still include <merge> tag?
  • Ewan
    Ewan over 5 years
    @NeonWarge There is a complete example at developer.android.com/topic/libraries/data-binding/…. It adds "Data binding doesn't support include as a direct child of a merge element"
  • Daniel Carpio Contreras
    Daniel Carpio Contreras over 5 years
    I've got an error message that says: "Only one layout element and one data element are allowed"
  • iCantC
    iCantC over 5 years
    In your answer you handled the setText event programmatically ,Instead of TextView if it would have been a Button , then how would you have handled its click event .I know that programmatically binding.includedLayout.button.setOnClickListener would be the alternative,but what if i want to use onClick attribute in XML itself ?
  • Khemraj Sharma
    Khemraj Sharma over 5 years
    You can pass OnClickListener to included layout. even you can pass anything in binding. Check this answer, if you need more help, let me know. stackoverflow.com/a/51722829/6891563
  • Elliptica
    Elliptica about 5 years
    When I do this, I just get a blank field for passedText. The only difference is I don't include the MainActivity code because I just want to pass the string resource in <include> and leave it like that. Why is it always blank though?
  • Martin Rajniak
    Martin Rajniak about 4 years
    @GeorgeMount it doesn't work for me with "app" namespace. It has to be "bind" namespace for it to generate correct code. Like this: bind:foo={something}
  • M. Wojcik
    M. Wojcik over 3 years
    @Elliptica As its databinding, I guess the value for passedText should be an ObservableField or a LiveData, otherwise it will never be actually loaded, right @Khemraj?
  • IgorGanapolsky
    IgorGanapolsky over 3 years
    This doesn't compile. Error: cannot find symbol
  • the_prole
    the_prole about 3 years
    I had to clean/rebuild because I switched over from findViewById.
  • Patrick
    Patrick almost 3 years
    I have this error: attribute foo not found.