178 lines
7.9 KiB
Plaintext
178 lines
7.9 KiB
Plaintext
page.title=Layout Tricks: Creating Efficient Layouts
|
|
@jd:body
|
|
|
|
<p>The Android UI toolkit offers several layout managers that are
|
|
rather easy to use and, most of the time, you only need the basic
|
|
features of these layout managers to implement a user interface.</p>
|
|
|
|
<p>Sticking to the basic features is unfortunately not the most efficient
|
|
way to create user interfaces. A common example is the abuse of
|
|
{@link android.widget.LinearLayout}, which leads to a proliferation of
|
|
views in the view hierarchy. Every view — or worse, every layout
|
|
manager — that you add to your application comes at a cost:
|
|
initialization, layout and drawing become slower. The layout pass can be
|
|
especially expensive when you nest several <code>LinearLayout</code>
|
|
that use the {@link android.R.attr#layout_weight weight}
|
|
parameter, which requires the child to be measured twice.</p>
|
|
|
|
<p>Let's consider a very simple and common example of a layout: a list item
|
|
with an icon on the left, a title at the top and an optional description
|
|
underneath the title. Here is what such an item looks like:</p>
|
|
|
|
<div style="text-align: center;"><img src="images/relativelayout_1.png" alt="Simple list item"></div>
|
|
|
|
<p>To clearly understand how the views, one {@link android.widget.ImageView} and
|
|
two {@link android.widget.TextView}, are positioned with respect to each other,
|
|
here is the wireframe of the layout as captured by <a
|
|
href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">HierarchyViewer</a
|
|
>:</p>
|
|
|
|
<div style="text-align: center;"><img src="images/relativelayout_wire_1.png" alt="Wireframe of the simple list item"></div>
|
|
|
|
<p>Implementing this layout is straightforward with <code>LinearLayout</code>.
|
|
The item itself is a horizontal <code>LinearLayout</code> with an
|
|
<code>ImageView</code> and a vertical <code>LinearLayout</code>, which contains
|
|
the two <code>TextView</code>. Here's the source code of this layout:</p>
|
|
|
|
<pre class="prettyprint"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
android:layout_width="fill_parent"
|
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
|
|
|
android:padding="6dip">
|
|
|
|
<ImageView
|
|
android:id="@+id/icon"
|
|
|
|
android:layout_width="wrap_content"
|
|
android:layout_height="fill_parent"
|
|
android:layout_marginRight="6dip"
|
|
|
|
android:src="@drawable/icon" />
|
|
|
|
<LinearLayout
|
|
android:orientation="vertical"
|
|
|
|
android:layout_width="0dip"
|
|
android:layout_weight="1"
|
|
android:layout_height="fill_parent">
|
|
|
|
<TextView
|
|
android:layout_width="fill_parent"
|
|
android:layout_height="0dip"
|
|
android:layout_weight="1"
|
|
|
|
android:gravity="center_vertical"
|
|
android:text="My Application" />
|
|
|
|
<TextView
|
|
android:layout_width="fill_parent"
|
|
android:layout_height="0dip"
|
|
android:layout_weight="1"
|
|
|
|
android:singleLine="true"
|
|
android:ellipsize="marquee"
|
|
android:text="Simple application that shows how to use RelativeLayout" />
|
|
|
|
</LinearLayout>
|
|
|
|
</LinearLayout></pre>
|
|
|
|
<p>This layout works but can be wasteful if you instantiate it for every list
|
|
item of a {@link android.widget.ListView}. The same layout can be rewritten
|
|
using a single {@link android.widget.RelativeLayout}, thus saving one view, and
|
|
even better one level in view hierarchy, per list item. The implementation of
|
|
the layout with a <code>RelativeLayout</code> remains simple:</p>
|
|
|
|
<pre class="prettyprint"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
android:layout_width="fill_parent"
|
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
|
|
|
android:padding="6dip">
|
|
|
|
<ImageView
|
|
android:id="@+id/icon"
|
|
|
|
android:layout_width="wrap_content"
|
|
android:layout_height="fill_parent"
|
|
|
|
android:layout_alignParentTop="true"
|
|
android:layout_alignParentBottom="true"
|
|
android:layout_marginRight="6dip"
|
|
|
|
android:src="@drawable/icon" />
|
|
|
|
<TextView
|
|
android:id="@+id/secondLine"
|
|
|
|
android:layout_width="fill_parent"
|
|
android:layout_height="26dip"
|
|
|
|
android:layout_toRightOf="@id/icon"
|
|
android:layout_alignParentBottom="true"
|
|
android:layout_alignParentRight="true"
|
|
|
|
android:singleLine="true"
|
|
android:ellipsize="marquee"
|
|
android:text="Simple application that shows how to use RelativeLayout" />
|
|
|
|
<TextView
|
|
android:layout_width="fill_parent"
|
|
android:layout_height="wrap_content"
|
|
|
|
android:layout_toRightOf="@id/icon"
|
|
android:layout_alignParentRight="true"
|
|
android:layout_alignParentTop="true"
|
|
android:layout_above="@id/secondLine"
|
|
android:layout_alignWithParentIfMissing="true"
|
|
|
|
android:gravity="center_vertical"
|
|
android:text="My Application" />
|
|
|
|
</RelativeLayout></pre>
|
|
|
|
<p>This new implementation behaves exactly the same way as the previous
|
|
implementation, except in one case. The list item we want to display has two
|
|
lines of text: the title and an <em>optional</em> description. When a
|
|
description is not available for a given list item, the application would simply
|
|
set the visibility of the second <code>TextView</code> to
|
|
{@link android.view.View#GONE}. This works perfectly with the <code>LinearLayout</code>
|
|
implementation but not with the <code>RelativeLayout</code> version:</p>
|
|
|
|
<div style="text-align: center;"><img src="images/relativelayout_2.png" alt="RelativeLayout and description GONE"></div>
|
|
<div style="text-align: center;"><img src="images/relativelayout_wire_2.png" alt="RelativeLayout and description GONE"></div>
|
|
|
|
<p>In a <code>RelativeLayout</code>, views are aligned with their parent, with the
|
|
<code>RelativeLayout</code> itself, or with other views. For instance, we declared that
|
|
the description is aligned with the bottom of the <code>RelativeLayout</code> and
|
|
that the title is positioned above the description and anchored to the
|
|
parent's top. With the description GONE, RelativeLayout doesn't know
|
|
where to position the title's bottom edge. To solve this problem, you
|
|
can use a very special layout parameter called
|
|
{@link android.R.attr#layout_alignWithParentIfMissing}.
|
|
</p>
|
|
|
|
<p>This boolean parameter simply tells RelativeLayout to use its own edges as
|
|
anchors when a constraint target is missing. For instance, if you position a
|
|
view to the right of a GONE view and set <code>alignWithParentIfMissing</code>
|
|
to <code>true</code>, <code>RelativeLayout</code> will instead anchor the view
|
|
to its left edge. In our case, using <code>alignWithParentIfMissing</code> will
|
|
cause <code>RelativeLayout</code> to align the title's bottom with its own
|
|
bottom. The result is the following:</p>
|
|
|
|
<div style="text-align: center;"><img src="images/relativelayout_3.png" alt="RelativeLayout, description GONE and alignWithParentIfMissing"></div>
|
|
<div style="text-align: center;"><img src="images/relativelayout_wire_3.png" alt="RelativeLayout, description GONE and alignWithParentIfMissing"></div>
|
|
|
|
<p>The
|
|
behavior of our layout is now perfect, even when the description is
|
|
GONE. Even better, the hierarchy is simpler and because we are not
|
|
using LinearLayout's weights it's also more efficient. The difference
|
|
between the two implementations becomes obvious when comparing the view
|
|
hierarchies in HierarchyViewer:</p>
|
|
|
|
<div style="text-align: center;"><img src="images/layouts_comparison_small.png" alt="LinearLayout vs RelativeLayout"></div>
|
|
|
|
<p>Again, the difference will be much more important when you use such a layout
|
|
for every item in a ListView for instance. Hopefully this simple
|
|
example showed you that getting to know your layouts is the best way to
|
|
learn how to optimize your UI.</p>
|