85

I am unable to override attributes when using <include> in my Android layout files. When I searched for bugs, I found Declined Issue 2863:

"include tag is broken (overriding layout params never works)"

Since Romain indicates this works in the test suites and his examples, I must be doing something wrong.

My project is organized like this:

res/layout
  buttons.xml

res/layout-land
  receipt.xml

res/layout-port
  receipt.xml

The buttons.xml contains something like this:

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

  <Button .../>

  <Button .../>
</LinearLayout>

And the portrait and landscape receipt.xml files look something like:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

  ...

  <!-- Overridden attributes never work. Nor do attributes like
       the red background, which is specified here. -->
  <include
      android:id="@+id/buttons_override"
      android:background="#ff0000"
      android:layout_width="fill_parent"
      layout="@layout/buttons"/>

</LinearLayout>

What am I missing?

1
  • This question is referred to by the Android developer tools when you attempt to use include in a way that isn't supported.
    – ThomasW
    Aug 22, 2018 at 9:18

3 Answers 3

135

I just found the issue. First, you can only override layout_* attributes, so the background won't work. That is documented behavior and simply an oversight on my part.

The real problem is found in LayoutInflater.java:

// We try to load the layout params set in the <include /> tag. If
// they don't exist, we will rely on the layout params set in the
// included XML file.
// During a layoutparams generation, a runtime exception is thrown
// if either layout_width or layout_height is missing. We catch
// this exception and set localParams accordingly: true means we
// successfully loaded layout params from the <include /> tag,
// false means we need to rely on the included layout params.
ViewGroup.LayoutParams params = null;
try {
   params = group.generateLayoutParams(attrs);
} catch (RuntimeException e) {
   params = group.generateLayoutParams(childAttrs);
} finally {
   if (params != null) {
     view.setLayoutParams(params);
   }
}

If the <include> tag does not include both layout_width and layout_height, the RuntimeException occurs and is silently handled, without any log statement even.

The solution is to always include both layout_width and layout_height when using the <include> tag, if you want to override any of the layout_* attributes.

My example should change to:

<include
      android:id="@+id/buttons_override"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      layout="@layout/buttons"/>
2
  • 34
    This is ridiculous. I've never been able to get this to work, and I even saw the documentation mention needing both height and width if trying to override dimensions, which I assumed were height and width. However, all I was trying to override is margin, which isn't really a dimension. Why the heck do I need to specify both of those or even any of those when all I want to change is the layout_marginRight? Grrr, Android, sometimes you frustrate me too much. Dec 14, 2010 at 2:06
  • 1
    FYI Android Lint will give you an error (Layout parameter layout_height ignored unless layout_width is also specified on <include> tag) if you are not overriding both height and width attributes
    – binary
    Jan 16, 2015 at 21:46
10

I submitted an enhancement request to allow all included attributes to be overridden:

Suppose I have two identical layouts other than the values of a TextView field. Presently, I either have modify the layout at runtime or duplicate the XML.

For example to pass two parameters with values "hello" and "world" to layout1:

<include layout="@layout/layout1a" params="textView=hello|editText=world" />

layout1a.xml:

<merge><TextView text="@param/textView"><EditText hint="@param/editText"></merge>

An alternate implementation would break encapsulation and would allow the include statement to override values like:

<include layout="@layout/layout1b" overrides="@id/textView.text=hello|@id/editText.hint=world" />

layout1b.xml:

<merge><TextView id="@+id/textView"><EditText hint="@+id/editText"></merge>

1
  • 1
    Taking into consideration the new databinding stuff, the <include> is used even more often now, attr overriding is a really must have feature Feb 25, 2016 at 16:02
1

I found I sometimes miss including the android:id tag when using the GUI builder in Eclipse. Making sure (when I notice) that I add into a TextView from the builder , the id I'm using in the ListView layout.

<TextView android:text="@+id/textView1"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
...

becomes

<TextView android:id="@+id/textView1"
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
...

Instead of getting 'false' 'false' I get :) and includes working ok.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.