Android XML 布局的“包含”标签真的有用吗?

在 Android 布局文件中使用 < include > 时,我无法覆盖属性。当我搜索 bug 时,我发现了拒绝 第2863期:

“ include 标记被破坏(重写布局参数从不起作用)”

既然 Romain 指出这在测试套件和他的示例中是可行的,那么我一定是做错了什么。

我的项目是这样组织的:

res/layout
buttons.xml


res/layout-land
receipt.xml


res/layout-port
receipt.xml

Xml 包含以下内容:

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

并且纵向和横向 Receipt.xml 文件看起来像这样:

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

我错过了什么?

30530 次浏览

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

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.

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>