Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition11.3. LayoutsLayouts are Android's solution to the variety of screens that come
on Android devices: they can have different pixel densities, different
dimensions, and different aspect ratios. Typical Android devices, such as
the HTC G1 mobile phone, even allow changing the screen orientation
(portrait or landscape) while applications are running, so the layout
infrastructure needs to be able to respond on the fly. Layouts are
intended to give developers a way to express the physical relationship of
Views as they are drawn on the screen. As Android inflates the Layout, it
uses the developer requests to come up with a screen layout that best
approximates what the developer has asked for. Looking a little deeper, layouts in Android are in the form of a
tree, with a single root and a hierarchy of Views. Look back at any of the
XML Layout files in the previous section and you'll see that the XML tags
create just such a hierarchy, with a screen Layout as the root of the
tree. Each View in the tree is termed the parent of the Views it contains
and the child of the View that contains it. Layout is a two-pass
process:
Measure pass Traversing the tree from the root, each View in the layout
records its dimensional request—in other words, how much vertical
height and horizontal width it needs to display itself in the final
display.
Layout pass Again traversing the tree from the root, each parent View
uses the available layout information to position its children as
requested. If the requests can't be followed explicitly, Android
does its best to make everything fit on the screen. If there are no
requests given, it uses a default set of layout parameters. Each
parent can pass layout information on to its children, telling them
where they are positioned and what screen dimensions they have been
granted (they might get less than they requested).
A Layout is a View itself, so there's nothing wrong with having
multiple Layouts in a single layout XML file—they just have to be arranged
in a hierarchy. So it's perfectly valid to have a vertical LinearLayout
that includes a TableLayout as one of its rows. You'll learn a lot more
about layouts in Chapter 12. 11.3.1. Frame LayoutThe Frame Layout is sort of a null layout specification. It
reserves space on the screen for a single View to be drawn, and the View
is always located at the upper left of the space. There is no way to
specify a different location for the View, and there can be only one
View in the Layout. If more than one View is defined in the layout file,
they are just drawn on top of each other, all pinned to the upper-left
corner. 11.3.2. LinearLayoutLinearLayouts are used extensively in Android applications, and we used
them in example code earlier. A LinearLayout asks that the contained
Views be layed out as either a series of rows (vertical LinearLayout) or
a series of columns (horizontal LinearLayout). In a vertical LinearLayout,
all the rows are the same width (the width of the widest child). In a
horizontal LinearLayout, there is one row of Views, all the same height
(the height of the tallest child). Figure 11-11
shows an example of a vertical LinearLayout, and Figure 11-12 is an example
of a horizontal one. Both have EditText Views as children. Example 11-9 shows the XML
resource file that produces the vertical layout, and Example 11-10 shows the file that
created the horizontal one. Example 11-9. Vertical LinearLayout resource file<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="EditText1"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="EditText2"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="EditText3"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="EditText4"
/>
</LinearLayout> |

Example 11-10. Horizontal LinearLayout resource file<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<EditText
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="E1"
/>
<EditText
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="E2"
/>
<EditText
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="E3"
/>
<EditText
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:text="E4"
/>
</LinearLayout> |

The horizontal layout might not look exactly as you would think:
how come E4 is narrower than the other three? The answer is that there
is a default minimum width for an EditText. If you build and run the
horizontal example and type something into EditText E1, you'll see that
it expands in width as the line gets longer, which is just what we asked
for with android:layout_width="wrap_content". In addition to the usual dimensional parameters for child Views
(width, height, padding), you can
include a weight for each child (attribute
android:layout_weight=;weight). The weight tells the
layout manager how you want to use unfilled space, and defaults to a
value of 0. If you specify children with weights greater than zero, the
layout manager will allocate unused space to each child in proportion to
its weight. Figure 11-13
shows an example of a LinearLayout containing four EditTexts. The first
two have no weights assigned. EditText3 has a weight of 1 and EditText4
has a weight of 2. The effect is to make EditText4 twice as big as
EditText3, while EditText1 and EditText2 just split whatever space the
layout leaves over. 
11.3.3. TableLayoutA TableLayout is just what you'd expect: it lays out the included Views
in the form of a table (similar to an HTML table). We can create a table
of TextViews to show how you would create that kind of screen for an
application. Here's an example TableLayout XML file: <?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tblJobs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:text="Cell 11"
android:id="@+id/btnCel11"
android:layout_width="20dip"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/txtCell12"
android:layout_width="20dip"
android:layout_height="wrap_content"
android:text="Cell 12"
/>
<TextView
android:id="@+id/txtCell13"
android:layout_width="20dip"
android:layout_height="wrap_content"
android:text="Cell 13"
/>
<TextView
android:id="@+id/txtCell14"
android:layout_width="20dip"
android:layout_height="wrap_content"
android:text="Cell 14"
/>
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:text="Cell 21"
android:id="@+id/btnCo21"
android:layout_width="80dip"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/txtCell22"
android:layout_width="80dip"
android:layout_height="wrap_content"
android:text="Cell 22"
/>
<TextView
android:id="@+id/txtCell23"
android:layout_width="80dip"
android:layout_height="wrap_content"
android:text="Cell 23"
/>
<TextView
android:id="@+id/txtCell24"
android:layout_width="80dip"
android:layout_height="wrap_content"
android:text="Cell 24"
/>
</TableRow>
</TableLayout>Figure 11-14 shows the
resulting layout on the emulator screen. 
The structure of the XML file is pretty evident: the TableLayout
tags contain a list of TableRows that in turn contain the Views you want
to appear on each line of the table. Notice that the layout_width values are different in the two
rows—all the widths in the first row are specified as 20dip, whereas the widths in the second row
are specified as 28dip—yet the
columns line up on the screen. To preserve the look of a table, Android
makes each column as wide as the widest cell in that column. Of course, the cells are addressable from your Java code, and you
can add rows programmatically to the table, if that's what your
application needs to do. 11.3.4. AbsoluteLayoutAn AbsoluteLayout puts views on the screen wherever you tell it to. It doesn't
try to resize anything, and it doesn't try to line anything up; it just
puts things where it's told. You might think that it would be an easy
type of layout to use, since you don't have to second-guess how the
layout manager is going to rearrange things on your screen, but in
practice the use of AbsoluteLayout is a bad idea for almost all
applications. You usually want your application to run on as many
Android devices as possible, and the strength of the Android layout
manager is that it will automatically adapt your screen layout from
device to device. AbsoluteLayout bypasses most of the layout manager,
and while your application may look perfect on the device you used for
development, the odds are very good that it will look terrible on other
Android devices. That warning aside, let's take a look at an AbsoluteLayout XML
file: <?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Upper Left"
android:layout_x="0.0px"
android:layout_y="0.0px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Middle"
android:layout_x="140.0px"
android:layout_y="200.0px"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Lower Right"
android:layout_x="240.0px"
android:layout_y="400.0px"
/>
</AbsoluteLayout>
As with any dimension in a layout file, the positions can be expressed in pixels (px),
device-independent pixels (dp), scaled pixels
(sp), inches (in), or millimeters
(mm), and the dimension has to be a floating-point
number. (For more about expressing sizes, see Dimensions in Android in Chapter 4.) Figure 11-15 shows
the resulting screen layout. Obviously, the position (0, 0) is the
upper-left corner of the display, and the View is properly flush with
the corner. The lower-right corner on the emulator is supposed to be
(320, 480), but the View appears to be a little shy of that in both
dimensions. 
Just to caution against the use of AbsoluteLayout again, we
suggest you try changing the emulator skin to show the screen in landscape mode (enter
emulator -skin HVGA-L from a
command or terminal window before you run the application), and you can
see in Figure 11-16 that the
application no longer looks right.
11.3.5. RelativeLayoutWe've used RelativeLayout, often in combination with
LinearLayout, throughout the MJAndroid application. The advantage of
RelativeLayout is that you can express the relative positioning of the
Views in the screen, and the layout manager will do its best to fit them
all on the screen in the proper relations. An example follows: <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/txtText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text1"
android:gravity="top"
android:layout_alignParentRight="true"
/>
<TextView
android:id="@+id/txtText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text2"
android:layout_below="@+id/txtText1"
/>
<Button
android:id="@+id/btnButton1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:text="Button1"
android:layout_below="@+id/txtText2"
/>
<Button
android:id="@+id/btnButton2"
android:layout_width="150dp"
android:layout_height="100dp"
android:text="Button2"
android:layout_toRightOf="@+id/btnButton1"
android:layout_alignTop="@+id/btnButton1"
/>
</RelativeLayout>Figure 11-17 shows
what this looks like in portrait mode (the emulator default), and Figure 11-18 shows it
in landscape mode. The layout manager has adjusted the
arrangements in each case to match the layout
hints we gave in the XML. 

|