Next   Previous section   Next section

Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition

11.3. Layouts

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

The 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. LinearLayout

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

Figure 11-11. Vertical 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>

Figure 11-12. Horizontal 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:lay⁠out_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.

Figure 11-13. Weighted LinearLayout


11.3.3. TableLayout

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

Figure 11-14. TableLayout


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

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

Figure 11-15. AbsoluteLayout


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.

Figure 11-16. Same AbsoluteLayout in landscape mode


11.3.5. RelativeLayout

We'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.

Figure 11-17. RelativeLayout in portrait mode


Figure 11-18. RelativeLayout in landscape mode


          
    Next   Previous section   Next section