Assembling a Graphical Interface

Appportunity

Build your own Android App Dev Empire

Get Instant Access

The Android UI framework provides both a complete set of drawing tools with which to build a UI and a rich collection of prebuilt components based on these tools. As we will see in Chapter 12, the framework graphics tools provide plenty of support for applications that need to create their own controls or render special views. On the other hand, many applications may work very well using only canned widgets from the toolkit. In fact, as we saw in Chapter 9, the MapActivity and MyLocationOverlay classes make it possible to create extremely sophisticated applications without doing any custom drawing at all.

We've already used the term "widget" once or twice, without explicitly defining it. Recall that the screen is a rendered by a tree of components. In the Android UI framework, these components are all subclasses of android.view.View. The components that are leaves or nearly leaves do most of the actual drawing and are, in the context of an application UI, commonly called widgets.

The internal nodes, sometimes called Container Views, are special components that can have other components as children. In the Android UI framework, Container Views are subclasses of android.view.ViewGroup, which, of course, is in turn a subclass of View. Typically, they do very little drawing. Instead, they are responsible for arranging their child components on the screen and keeping them arranged as the display changes shape, orientation, and so on. Doing this can be quite complex.

You have already seen a very simple View coded up in "Writing Hello-World" on page 22. That application created a trivial TextView and displayed it. There is no way to add anything to that application, because the root View is a TextView, which cannot be a container for other components. To create more complex displays, it is necessary to assemble a tree of containers. Example 10-1 shows an application with a view tree that is three layers deep. A vertical linear layout contains two horizontal linear layouts. Each of the horizontal layouts, in turn, contains two widgets.

Example 10-1. A complex view tree package com.oreilly.android.intro;

import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.Gravity; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout;

public class AndroidDemo extends Activity { private LinearLayout root;

@Override public void onCreate(Bundle state) { super.onCreate(state);

LinearLayout.LayoutParams containerParams = new LinearLayout.LayoutParams(

ViewGroup.LayoutParams.FILL_PARENT,

ViewGroup.LayoutParams.WRAP_CONTENT,

LinearLayout.LayoutParams widgetParams = new LinearLayout.LayoutParams(

ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 1.0F);

root = new LinearLayout(this); root.setOrientation(LinearLayout.VERTICAL); root.setBackgroundColor(Color.LTGRAY); root.setLayoutParams(containerParams);

LinearLayout ll = new LinearLayout(this);

ll.setOrientation(LinearLayout.HORIZONTAL);

ll.setBackgroundColor(Color.GRAY);

ll.setLayoutParams(containerParams);

root.addView(ll);

EditText tb = new EditText(this);

tb.setText(R.string.defaultLeftText);

tb.setFocusable(false);

tb.setLayoutParams(widgetParams);

ll.addView(tb);

tb = new EditText(this);

tb.setText(R.string.defaultRightText);

tb.setFocusable(false);

tb.setLayoutParams(widgetParams);

ll.addView(tb);

ll = new LinearLayout(this);

ll.setOrientation(LinearLayout.HORIZONTAL);

ll.setBackgroundColor(Color.DKGRAY);

ll.setLayoutParams(containerParams);

root.addView(ll);

Button b = new Button(this);

b.setText(R.string.labelRed);

b.setTextColor(Color.RED);

b.setLayoutParams(widgetParams);

ll.addView(b);

b.setText(R.string.labelGreen);

b.setTextColor(Color.GREEN);

b.setLayoutParams(widgetParams);

ll.addView(b);

setContentView(root);

Note that the code preserves a reference to the root of the View tree for later use.

This example uses three LinearLayout widgets. A LinearLayout, just as its name implies, is a View that displays its children in a row or column, as determined by its orientation property. The child views are displayed in the order in which they are added to the LinearLayout (regardless of the order in which they were created), in the directions familiar to Western readers: left to right and top to bottom. The button labeled "Green", for instance, is in the lower righthand corner of this layout, because it is the second thing added to the horizontal LinearLayout View, which was, in turn, the second thing added to the vertical LinearLayout (the root).

Figure 10-2 shows what the results might look like to the user. The seven Views in the tree are structured as shown in Figure 10-3.

Figure 10-2. The View as it appears on the screen

LinearLayout (vertical)

LinearLayout

LinearLayout

(horizontal)

(horizontal)

Text

Text

Red button

Green button

Figure 10-3. Hierarchy of objects in the View

Chapter 8 explained that the Android framework provides a convenient capability for separating data resources from code. This is particularly useful in building view component layouts. The previous example can be replaced with the dramatically simpler code in Example 10-2 and the XML definition of the layout in Example 10-3.

Example 10-2. Complex View using a layout resource package com.oreilly.android.intro;

import android.app.Activity; import android.os.Bundle;

* Android UI demo program

public class AndroidDemo extends Activity { private LinearLayout root;

^Override public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.main); root = (LinearLayout) findViewByld(R.id.root);

Example 10-3. Complex View layout resource

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root" android:orientation="vertical" android:background="@drawable/lt_gray" android:layout_width="fill_parent" android:layout_height="wrap_content">

<LinearLayout android:orientation="horizontal" android:background="@drawable/gray" android:layout_width="fill_parent" android:layout_height="wrap_content">

<EditText android:id="@+id/textl"

android:text="@string/defaultLeftText"

android:focusable="false"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_weight="l"/>

<EditText android:id="@+id/text2"

android:text="@string/defaultRightText"

android:focusable="false"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_weight="l"/>

</LinearLayout>

<LinearLayout android:orientation="horizontal" android:background="@drawable/dk_gray" android:layout_width="fill_parent" android:layout_height="wrap_content">

<Button android:id="@+id/buttonl"

android:text="@string/labelRed"

android:textColor="@drawable/red"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_weight="l"/>

<Button android:id="@+id/button2" android:text="@string/labelGreen" android:textColor="@drawable/green" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"/> </LinearLayout> </LinearLayout>

This version of the code, like the first one, also preserves a reference to the root of the View tree. It does this by tagging a widget in the XML layout (the root LinearLayout, in this case) with an android:id tag, and then using the findViewById method from the Activity class to recover the reference.

It is a very good idea to get into the habit of using a resource to define your View tree layout. Doing so allows you to separate the visual layout from the code that brings it to life. This way, you can tinker with the layout of a screen without recompiling. Further, if the history of other UI frameworks is any indication, there will eventually be tools for Android that allow you to compose screens, creating their XML definitions, using a visual UI editor.

Was this article helpful?

0 0

Post a comment