177

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?

Tlaloc-ES
  • 4,825
  • 7
  • 38
  • 84
Kamil Nękanowicz
  • 6,254
  • 7
  • 34
  • 51

8 Answers8

300

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"/>
   ....
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
George Mount
  • 20,708
  • 2
  • 73
  • 61
  • 16
    1.0-rc4 now fixes the problem of needing the unnecessary variable. You can now use simply: ``. You still need the id so that it will produce a public field for you so that you can access the Button View. – George Mount Oct 09 '15 at 19:47
  • 2
    Are anyone else having problems binding click events on the layout though? – Nilzor Feb 29 '16 at 10:32
  • Are you using data binding syntax? `android:onClick="@{myObj.clickHandler}"` – George Mount Feb 29 '16 at 23:24
  • 5
    Databinding with include support. https://developer.android.com/topic/libraries/data-binding/index.html#includes – Sowmia Sundararajan Jul 15 '16 at 18:53
  • 2
    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. – Rishabh876 Jan 19 '18 at 08:47
  • @GeorgeMount How to call static method from layout element like `android:text="{MyClass.getUser().name}"` ? – Khemraj Sharma Aug 09 '18 at 11:00
  • You can do that either by importing the class name using the `` in the `data` section or by using the fully qualified class name in the expression: `android:text="@{com.example.MyClass.user.name}"` – George Mount Aug 09 '18 at 17:49
  • what if you want to pass in two parameters/ – CodingTT Oct 17 '18 at 19:05
  • If you want to pass two parameters, you can just do that. `` where `param1` and `param2` are variables in your included layout. – George Mount Oct 18 '18 at 01:04
  • 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 tag? – Neon Warge Oct 19 '18 at 00:58
  • 1
    @NeonWarge There is a complete example at https://developer.android.com/topic/libraries/data-binding/expressions#imports_variables_and_includes. It adds "Data binding doesn't support include as a direct child of a merge element" – Ewan Feb 23 '19 at 13:11
  • I've got an error message that says: "Only one layout element and one data element are allowed" – Daniel Carpio Contreras Feb 24 '19 at 18:33
  • @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}` – Martin Rajniak Mar 30 '20 at 16:39
  • I had to clean/rebuild because I switched over from findViewById. – the_prole Jun 28 '21 at 18:52
  • Note that `foo` or any other name you choose must be **lowercase**. – Iman Marashi Aug 03 '22 at 03:15
  • @Patrick no matter, its work. – Iman Marashi Aug 03 '22 at 03:16
74

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

Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212
  • 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 ? – iCantC Mar 10 '19 at 12:06
  • 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. https://stackoverflow.com/a/51722829/6891563 – Khemraj Sharma Mar 10 '19 at 16:20
  • 1
    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 and leave it like that. Why is it always blank though? – Elliptica May 01 '19 at 05:08
  • @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? – M. Wojcik Jan 04 '21 at 20:58
  • 4
    This doesn't compile. `Error: cannot find symbol` – IgorGanapolsky Jan 06 '21 at 19:23
23

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");
Sadeq Hitex
  • 269
  • 2
  • 9
6

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}" />
Rodrigo Salomao
  • 143
  • 1
  • 10
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)
Derlin
  • 9,572
  • 2
  • 32
  • 53
  • 1
    This was the only solution that ended up working for me, otherwise I get kept receiving the error "error: cannot find symbol this.totalAmtContainer.setMonthly_amt(monthlyAmt);" with my variable name being "monthlyAmt" – yazmnh87 Apr 05 '23 at 12:45
0

it seems you have empty data tag in your xml file please cross check, it is making cause to not generate include layout file

 <data>

</data>

remove this tag if your not using, will solve the problem

Mohd Qasim
  • 896
  • 9
  • 20
0

I would like to add, I had the similar problem. My problem was that the variable name was title, the same as id name. There was no compile error. (Not 100% sure was that a problem, I also clean the project)

<?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"
        xmlns:tools="http://schemas.android.com/tools">
<data>

    <variable
        name="title"
        type="String" />
</data>
...
<androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/title"...>
<androidx.appcompat.widget.AppCompatTextView>
...
</layout>
I.Step
  • 613
  • 6
  • 22
0

Just you make sure your include layout has enabled dataBinding tag

below code is my layout that I include in other layout

<data>

    <variable
        name="backBinding"
        type="String" />

</data>

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cl_back"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/dimen_30"
    android:layout_marginTop="@dimen/dimen_30"
    android:padding="@dimen/dimen_2"
    app:layout_constraintStart_toStartOf="parent">

    <ImageView
        android:id="@+id/iv_back"
        android:layout_width="@dimen/dimen_10"
        android:layout_height="@dimen/dimen_20"
        android:contentDescription="@string/back"
        android:src="@drawable/ic_back"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_back"
        style="@style/AidoFTTextStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/dimen_10"
        android:text="@string/face_training"
        android:textSize="@dimen/text_20"
        app:layout_constraintBottom_toBottomOf="@id/iv_back"
        app:layout_constraintStart_toEndOf="@id/iv_back"
        app:layout_constraintTop_toTopOf="@id/iv_back" />

</androidx.constraintlayout.widget.ConstraintLayout>

here I am including in my main layout

<data>

    <variable
        name="viewModel"
        type="com.ingenDynamic.coreaidokotlin.viewModels.VideoCallViewModel" />

</data>

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/aido_main_background"
    tools:context=".ui.aidoVideoCall.ContactActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/back_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/dimen_20"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/cl_appBar">

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

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

and directly I can access my included layout

binding.backLayout.setOnClickListener { finish() }
binding.back.tvBack.text = getText(R.string.video_call)
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141