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><include /></code> tag in XML layouts, to 7reuse and share your layout code. This article explains the <code><merge /></code> tag and how 8it complements the <code><include /></code> tag.</p> 9 10<p>The <code><merge /></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"><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 19 android:layout_width="fill_parent" 20 android:layout_height="fill_parent"> 21 22 <ImageView 23 android:layout_width="fill_parent" 24 android:layout_height="fill_parent" 25 26 android:scaleType="center" 27 android:src="@drawable/golden_gate" /> 28 29 <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" /> 41 42</FrameLayout></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><merge /></code> tag comes in handy. When the 64{@link android.view.LayoutInflater} encounters this tag, it skips it and adds 65the <code><merge /></code> children to the <code><merge /></code> 66parent. Confused? Let's rewrite our previous XML layout by replacing the 67<code>FrameLayout</code> with <code><merge /></code>:</p> 68 69<pre class="prettyprint"><merge xmlns:android="http://schemas.android.com/apk/res/android"> 70 71 <ImageView 72 android:layout_width="fill_parent" 73 android:layout_height="fill_parent" 74 75 android:scaleType="center" 76 android:src="@drawable/golden_gate" /> 77 78 <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" /> 90 91</merge></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><merge /></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><merge /></code> can be useful in 104other situations though. For instance, it works perfectly when combined with the 105<code><include /></code> tag. You can also use <code><merge 106/></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"><merge 114 xmlns:android="http://schemas.android.com/apk/res/android" 115 xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge"> 116 117 <ImageView 118 android:layout_width="fill_parent" 119 android:layout_height="fill_parent" 120 121 android:scaleType="center" 122 android:src="@drawable/golden_gate" /> 123 124 <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" /> 136 137</merge></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><merge /></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"><merge xmlns:android="http://schemas.android.com/apk/res/android"> 178 <include 179 layout="@layout/okcancelbar_button" 180 android:id="@+id/okcancelbar_ok" /> 181 182 <include 183 layout="@layout/okcancelbar_button" 184 android:id="@+id/okcancelbar_cancel" /> 185</merge></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><merge /></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><merge /></code> can only be used as the root tag of an XML layout</li> 197<li>When inflating a layout starting with a <code><merge /></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