• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Layout Tricks: Merging Layouts
2parent.title=Articles
3parent.link=../browser.html?tag=article
4@jd:body
5
6<p>The articles showed you how to use the <code>&lt;include /&gt;</code> tag in XML layouts, to
7reuse and share your layout code. This article explains the <code>&lt;merge /&gt;</code> tag and how
8it complements the  <code>&lt;include /&gt;</code> tag.</p>
9
10<p>The <code>&lt;merge /&gt;</code> tag was created for the purpose of
11optimizing Android layouts by reducing the number of levels in view trees. It's
12easier to understand the problem this tag solves by looking at an example. The
13following XML layout declares a layout that shows an image with its title on top
14of it. The structure is fairly simple; a {@link android.widget.FrameLayout} is
15used to stack a {@link android.widget.TextView} on top of an
16{@link android.widget.ImageView}:</p>
17
18<pre class="prettyprint">&lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
19    android:layout_width="fill_parent"
20    android:layout_height="fill_parent"&gt;
21
22    &lt;ImageView
23        android:layout_width="fill_parent"
24        android:layout_height="fill_parent"
25
26        android:scaleType="center"
27        android:src="&#64;drawable/golden_gate" /&gt;
28
29    &lt;TextView
30        android:layout_width="wrap_content"
31        android:layout_height="wrap_content"
32        android:layout_marginBottom="20dip"
33        android:layout_gravity="center_horizontal|bottom"
34
35        android:padding="12dip"
36
37        android:background="#AA000000"
38        android:textColor="#ffffffff"
39
40        android:text="Golden Gate" /&gt;
41
42&lt;/FrameLayout&gt;</pre>
43
44<p>This layout renders nicely and nothing seems wrong with it:</p>
45
46<div style="text-align: center;"><img src="images/merge1.jpg" alt="A FrameLayout is used to overlay a title on top of an image"></div>
47
48<p>Things get more interesting when you inspect the result with <a
49href="{@docRoot}guide/developing/debugging/debugging-ui.html#hierarchyViewer">HierarchyViewer</a>.
50If you look closely at the resulting tree, you will notice that the
51<code>FrameLayout</code> defined in our XML file (highlighted in blue below) is
52the sole child of another <code>FrameLayout</code>:</p>
53
54<div style="text-align: center;"><img src="images/merge2.png" alt="A layout with only one child of same dimensions can be removed"></div>
55
56<p>Since our <code>FrameLayout</code> has the same dimension as its parent, by
57the virtue of using the <code>fill_parent</code> constraints, and does not
58define any background, extra padding or a gravity, it is <em>totally
59useless</em>. We only made the UI more complex for no good reason. But how could
60we get rid of this <code>FrameLayout</code>? After all, XML documents require a
61root tag and tags in XML layouts always represent view instances.</p>
62
63<p>That's where the <code>&lt;merge /&gt;</code> tag comes in handy. When the
64{@link android.view.LayoutInflater} encounters this tag, it skips it and adds
65the <code>&lt;merge /&gt;</code> children to the <code>&lt;merge /&gt;</code>
66parent. Confused? Let's rewrite our previous XML layout by replacing the
67<code>FrameLayout</code> with <code>&lt;merge /&gt;</code>:</p>
68
69<pre class="prettyprint">&lt;merge xmlns:android="http://schemas.android.com/apk/res/android"&gt;
70
71    &lt;ImageView
72        android:layout_width="fill_parent"
73        android:layout_height="fill_parent"
74
75        android:scaleType="center"
76        android:src="&#64;drawable/golden_gate" /&gt;
77
78    &lt;TextView
79        android:layout_width="wrap_content"
80        android:layout_height="wrap_content"
81        android:layout_marginBottom="20dip"
82        android:layout_gravity="center_horizontal|bottom"
83
84        android:padding="12dip"
85
86        android:background="#AA000000"
87        android:textColor="#ffffffff"
88
89        android:text="Golden Gate" /&gt;
90
91&lt;/merge&gt;</pre>
92
93<p>With this new version, both the <code>TextView</code> and the
94<code>ImageView</code> will be added directly to the top-level
95<code>FrameLayout</code>. The result will be visually the same but the view
96hierarchy is simpler:</p>
97
98<div style="text-align: center;"><img src="images/merge3.png" alt="Optimized view hierarchy using the merge tag"></div>
99
100<p>Obviously, using <code>&lt;merge /&gt;</code> works in this case because the
101parent of an activity's content view is always a <code>FrameLayout</code>. You
102could not apply this trick if your layout was using a <code>LinearLayout</code>
103as its root tag for instance. The <code>&lt;merge /&gt;</code> can be useful in
104other situations though. For instance, it works perfectly when combined with the
105<code>&lt;include /&gt;</code> tag. You can also use <code>&lt;merge
106/&gt;</code> when you create a custom composite view. Let's see how we can use
107this tag to create a new view called <code>OkCancelBar</code> which simply shows
108two buttons with customizable labels. You can also <a
109href="http://progx.org/users/Gfx/android/MergeLayout.zip">download the complete
110source code of this example</a>. Here is the XML used to display this custom
111view on top of an image:</p>
112
113<pre class="prettyprint">&lt;merge
114    xmlns:android="http://schemas.android.com/apk/res/android"
115    xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge"&gt;
116
117    &lt;ImageView
118        android:layout_width="fill_parent"
119        android:layout_height="fill_parent"
120
121        android:scaleType="center"
122        android:src="&#64;drawable/golden_gate" /&gt;
123
124    &lt;com.example.android.merge.OkCancelBar
125        android:layout_width="fill_parent"
126        android:layout_height="wrap_content"
127        android:layout_gravity="bottom"
128
129        android:paddingTop="8dip"
130        android:gravity="center_horizontal"
131
132        android:background="#AA000000"
133
134        okCancelBar:okLabel="Save"
135        okCancelBar:cancelLabel="Don't save" /&gt;
136
137&lt;/merge&gt;</pre>
138
139<p>This new layout produces the following result on a device:</p>
140
141<div style="text-align: center;"><img src="images/merge4.jpg" alt="Creating a custom view with the merge tag"></div>
142
143<p>The source code of <code>OkCancelBar</code> is very simple because the two
144buttons are defined in an external XML file, loaded using a
145<code>LayoutInflate</code>. As you can see in the following snippet, the XML
146layout <code>R.layout.okcancelbar</code> is inflated with the
147<code>OkCancelBar</code> as the parent:</p>
148
149<pre class="prettyprint">public class OkCancelBar extends LinearLayout {
150    public OkCancelBar(Context context, AttributeSet attrs) {
151        super(context, attrs);
152        setOrientation(HORIZONTAL);
153        setGravity(Gravity.CENTER);
154        setWeightSum(1.0f);
155
156        LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);
157
158        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);
159
160        String text = array.getString(R.styleable.OkCancelBar_okLabel);
161        if (text == null) text = "Ok";
162        ((Button) findViewById(R.id.okcancelbar_ok)).setText(text);
163
164        text = array.getString(R.styleable.OkCancelBar_cancelLabel);
165        if (text == null) text = "Cancel";
166        ((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
167
168        array.recycle();
169    }
170}</pre>
171
172<p>The two buttons are defined in the following XML layout. As you can see, we
173use the <code>&lt;merge /&gt;</code> tag to add the two buttons directly to the
174<code>OkCancelBar</code>. Each button is included from the same external XML
175layout file to make them easier to maintain; we simply override their id:</p>
176
177<pre class="prettyprint">&lt;merge xmlns:android="http://schemas.android.com/apk/res/android"&gt;
178    &lt;include
179        layout="&#64;layout/okcancelbar_button"
180        android:id="&#64;+id/okcancelbar_ok" /&gt;
181
182    &lt;include
183        layout="&#64;layout/okcancelbar_button"
184        android:id="&#64;+id/okcancelbar_cancel" /&gt;
185&lt;/merge&gt;</pre>
186
187<p>We have created a flexible and easy to maintain custom view that generates
188an efficient view hierarchy:</p>
189
190<div style="text-align: center;"><img src="images/merge5.png" alt="The resulting hierarchy is simple and efficient"></div>
191
192<p>The <code>&lt;merge /&gt;</code> tag is extremely useful and can do wonders
193in your code. However, it suffers from a couple of limitations:</p>
194
195<ul>
196<li><code>&lt;merge /&gt;</code> can only be used as the root tag of an XML layout</li>
197<li>When inflating a layout starting with a <code>&lt;merge /&gt;</code>, you <strong>must</strong>
198specify a parent <code>ViewGroup</code> and you must set <code>attachToRoot</code> to
199<code>true</code> (see the documentation for
200{@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)} method)</li>
201</ul>
202
203