47

I have a main.xml file describing the layout of my main activity:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <include layout="@layout/mylayout" />
    <include layout="@layout/mylayout" />
    <include layout="@layout/mylayout" />
    <include layout="@layout/mylayout" />
    <include layout="@layout/mylayout" />
    <include layout="@layout/mylayout" />

</LinearLayout>

and its included layout xml file (mylayout.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mylayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello world" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

I just want to include "mylayout" in my main layout 5 times, but instead of seeing "hello world" 5 times, I want the TextView to contain custom text.

Is there any way to do this by setting some attribute on the include element to override the child TextView's text? What would be the best approach to take to accomplish this?

Matthew
  • 6,356
  • 9
  • 47
  • 59
  • 3
    This seems like a serious limitation that should be fixed. I just submitted a [bug report](https://code.google.com/p/android/issues/detail?id=36885). – Jeff Axelrod Aug 30 '12 at 16:42

4 Answers4

19

No, there is no way to pass parameters to the included layout other than the layout params using the <include> directive.

You can inflate the layout programatically and add them to your view. Add an id to the container in your main layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" />

Then in your Activity:

ViewGroup container = (ViewGroup)findViewById(R.id.container);
for (int i = 0; i < 6; i++) {
    View myLayout = getLayoutInflater.inflate(R.layout.mylayout, null);
    TextView tv = myLayout.findViewById(R.id.textView);
    tv.setText("my layout " + i);
    container.addView(myLayout); // you can pass extra layout params here too
}
aromero
  • 25,681
  • 6
  • 57
  • 79
  • 1
    don't forget to add the dataBinding element to your build.gradle file in the app module android { ... dataBinding { enabled = true } } – Amer Hadi Apr 20 '20 at 12:45
12

It is possible if you enable data binding:

In reuse_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
       <variable name="text" type="String"/>
    </data>
    <LinearLayout 
        android:id="@+id/mylayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{text}" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>
</layout>

when you call the reuse_layout.xml just add app:text attribute with it

<layout="@layout/reuse_layout" app:text="some tex" />
malliaridis
  • 389
  • 1
  • 12
  • 1
    Where does app:text get defined, as I am getting this error: "Error:(461) Error parsing XML: unbound prefix" when I compile and it is complaining about app:text attribute. Thanks! – Matt Oct 23 '17 at 21:16
  • 2
    In the layout "reuse_layout.xml" is where you can define variables. when you try to prase the data use prefix `app:` then followed by the name of the variable. I guess you try to send the string by using `@string` right? in this case please use `app:text="@{@string/your_string_key}"` – theerasan tonthongkam Oct 24 '17 at 09:34
  • Thanks, I guess there is just something I'm missing, because I get that error even with the code above copied as-is. – Matt Oct 25 '17 at 15:14
  • I am getting this error: "Error:(461) Error parsing XML: unbound prefix" – Rissmon Suresh Nov 26 '17 at 06:52
  • You need `xmlns:app="http://schemas.android.com/apk/res-auto"` in the root element (`layout`) to use the `app:` prefix. Then you'll need to place the literal string in a data-binding expression for it to be picked up, e.g., `app:text="@{"some text"}"`. See https://stackoverflow.com/a/58176538/686385 . – big_m Oct 01 '19 at 00:00
  • don't forget to add the dataBinding element to your build.gradle file in the app module android { ... dataBinding { enabled = true } } – Amer Hadi Apr 20 '20 at 12:45
5

https://developer.android.com/training/improving-layouts/reusing-layouts.html

You can set the android:id property of each include. That gives the id to the root element of the layout being included.

Get that view by id then find the subview you want to change the text on.

Kocus
  • 1,613
  • 17
  • 31
John Boker
  • 82,559
  • 17
  • 97
  • 130
  • Also I'm answering on my phone so its hard to type. – John Boker Jan 26 '12 at 02:39
  • I'm trying to see if there is a way to do this in the layout XML rather than in code. Is that not possible? – Matthew Jan 26 '12 at 02:44
  • 1
    I also met such problem and find that reusing the complex layout several times cost too much code to fill the property. Maybe it is better to copy paste same structure in layout xml. – tainy Sep 24 '14 at 04:15
1

I think I found an easy way, but it could create a lot of boilerplate code if the use case is high. but it's working perfectly for me

First Step:

Add data binding element to your build.gradle file in the app module

android{
...
dataBinding { enabled = true }
...
}

Second Step:

Create a layout file for your reusable layout

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

    <data>
        <variable
            name="text"
            type="String" />
    </data>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/card"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        app:cardBackgroundColor="@color/sortBtnBG"
        app:contentPadding="5dp"
        app:strokeColor="@color/cardStrokeColor"
        app:strokeWidth="1dp">

        <TextView
            android:id="@+id/card_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{text}"
            android:textColor="@color/black"
            android:textSize="16sp" />
    </com.google.android.material.card.MaterialCardView>



</layout>

add id for the elements you need to change, in my case, I am changing the text

Third Step:

Use your layout in your activity layout using <include/>

 <LinearLayout
        android:id="@+id/sorting_options"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp">

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

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

</LinearLayout>

make sure your give id to the <inlcude/>

Final Step:

In your activity.java file add this:

View custom_card1 = findViewById(R.id.customCard1);
TextView cc1 = view.findViewById(R.id.card_text);
cc1.setText("hello");

View custom_card2 = findViewById(R.id.customCard2);
TextView cc2 = view.findViewById(R.id.card_text);
cc2.setText("word");
Shibl
  • 87
  • 9