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.2. ViewGroups

ViewGroups are Views that contain child Views. Each ViewGroup class embodies a different set of assumptions about how to display its child Views. All ViewGroups descend from the android.view.ViewGroup class. Layouts, which we'll discuss later in the chapter, are a subset of ViewGroups.

11.2.1. Gallery and GridView

The Gallery ViewGroup (Figure 11-4) displays multiple items in a horizontally scrolling list. The currently selected item is locked in the center of the screen. Any items that approach the edge of the screen begin to fade, giving the user the impression that there may be more items "around the corner." The user can scroll horizontally through the items within the gallery. This ViewGroup is useful when you want to present a large set of possible choices to the user without using too much screen real estate.

Figure 11-4. The Gallery ViewGroup


A GridView (Figure 11-5, shown later) is very similar to a Gallery. Like a Gallery, the GridView displays many child Views that the user can manipulate. But in contrast to a Gallery, which is a one-dimensional list that the user can scroll horizontally, a GridView is a two-dimensional array that the user can scroll vertically.

The Gallery and GridView classes both descend from the AdapterView class, so you need a subclass of Adapter to provide a standardized way to access the underlying data. Any class that implements the Adapter class must implement the following abstract functions from that class:


int getCount

Returns the number of items in the data set represented by the Adapter.


Object getItem(int position)

Returns the object in the Adapter function (Adapter class) at the given position.


long getItem(int position)

Returns the row ID within the Adapter of the object at the given position.


View getView(int position, View convertView, ViewGroup parent)

Returns a View object that will display the data in the given position in the data set.

The ApiDemos application's views.Gallery1.java file shows off the Gallery ViewGroup nicely. The demo displays a variety of images for the user to select, and when the user does select one, the image's index number briefly appears as toast.

The ApiDemos application also includes two example GridView Activities that show how to use the GridView. We will not examine the GridView here, because the Gallery example is so similar.

Example 11-4 shows how to use a Gallery ViewGroup. Example 11-4 shows the XML layout file (gallery_1.xml).

Example 11-4. Layout file for Gallery example

<?xml version="1.0" encoding="utf-8"?>
<Gallery xmlns:android="http://schemas.android.com/apk/res/android" 
  android:id="@+id/gallery"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
/>

Here are some of the highlights of the layout code:

Figure 11-5. The GridView ViewGroup


Now we'll turn our attention to the Java implementation, Gallery1.java, shown in Example 11-5. We've modified the code from ApiDemos slightly to remove some features that do not add to our understanding of the Gallery ViewGroup.

Example 11-5. Java for Gallery: Gallery1.java

public class Gallery1 extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gallery_1);

        // Reference the Gallery view
        Gallery g = (Gallery) findViewById(R.id.gallery);
        // Set the adapter to our custom adapter (below)
        g.setAdapter(new ImageAdapter(this));

        // Set a item click listener, and just Toast the clicked position
        g.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView parent, View v, int position, long id) {
                Toast.makeText(Gallery1.this, "" + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

Here are some of the highlights of the code:

In Example 11-5, the setAdapter function tells the Gallery object to use the Image⁠Adap⁠ter object as its Adapter. Example 11-6 defines our ImageAdapter class. This ImageAdapter implements all of the abstract functions required in its base class, BaseAdapter. For the simple case of this demo, picture resources represent the data that the Gallery view is displaying. An integer array, mImageIds, contains the resource IDs of the picture resources.

Example 11-6. Java for Gallery's Adapter

    public class ImageAdapter extends BaseAdapter {
        int mGalleryItemBackground;

        private Context mContext;

        private Integer[] mImageIds = {
                R.drawable.gallery_photo_1,
                R.drawable.gallery_photo_2,
                R.drawable.gallery_photo_3,
                R.drawable.gallery_photo_4,
                R.drawable.gallery_photo_5,
                R.drawable.gallery_photo_6,
                R.drawable.gallery_photo_7,
                R.drawable.gallery_photo_8
        };

        public ImageAdapter(Context c) {
            mContext = c;

            TypedArray a = obtainStyledAttributes(android.R.styleable.Theme);
            mGalleryItemBackground = a.getResourceId(
                    android.R.styleable.Theme_galleryItemBackground, 0);
            a.recycle();
        }

        public int getCount() {
            return mImageIds.length;
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView i = new ImageView(mContext);

            i.setImageResource(mImageIds[position]);
            i.setScaleType(ImageView.ScaleType.FIT_XY);
            i.setLayoutParams(new Gallery.LayoutParams(136, 88));

            // The preferred Gallery item background
            i.setBackgroundResource(mGalleryItemBackground);

            return i;
        }
    }
}

Here are some of the highlights of the code:

11.2.2. ListView and ListActivity

ListView is similar to Gallery, but uses a vertically scrolling list in place of Gallery's horizontally scrolling list. To create a ListView that takes up the entire screen, Android provides the ListActivity class (Figure 11-6).

The ApiDemos application includes many examples of ListActivity. The simplest is the List1 class, which displays a huge number of cheese names in a list. The cheese names are kept in a simple String array (who knew there were that many cheese varieties!):

public class List1 extends ListActivity {

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

        // Use an existing ListAdapter that will map an array
        // of strings to TextViews
        setListAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mStrings));
    }

    private String[] mStrings = {
            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", 
              "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", 
              "Airedale",
            ...

Figure 11-6. ListActivity


Filling the ListView in the ListActivity is a simple matter of calling setListAdapter and passing it an ArrayAdapter that contains a reference to the list of strings.

11.2.3. ScrollView

A ScrollView is a container for another View that lets the user scroll that View vertically (a scrollbar is optional). A ScrollView often contains a LinearLayout, which in turn contains the Views that make up the form.

Don't confuse ScrollView with ListView. Both Views present the user with a scrollable set of Views, but the ListView is designed to display a set of similar things, such as the cheeses in the previous section. The ScrollView, on the other hand, allows an arbitrary View to scroll vertically. The Android documentation warns that one should never house a ListView within a ScrollView, because that defeats the performance optimizations of a ListView.

A ScrollView is a FrameLayout, which means that it can have only one child View. The most popular View for this purpose is a LinearLayout.

The following layout code from ApiDemos, scroll_view_2.xml, shows how to set up a ScrollView. The XML layout resource is sufficient; this example includes no extra Java code:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:scrollbars="none">
    <LinearLayout
        android:id="@+id/layout"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/scroll_view_2_text_1"/>

        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/scroll_view_2_button_1"/>

    </LinearLayout>
</ScrollView>

Here are some of the highlights of the code:

Figure 11-7. The first tab of a TabHost ViewGroup


Figure 11-8. The second tab of a TabHost ViewGroup


11.2.4. TabHost

Most modern UIs provide an interface element that lets the user flip through many pages of information quickly using tabs, with each "screen" of information available when its tab is pressed. Android's option is the TabHost View. Figures Figure 11-7 through Figure 11-10 show how it operates.

Figure 11-9. The third tab of a TabHost ViewGroup


Figure 11-10. The fourth tab of a TabHost ViewGroup


Android enables the developer to choose between three different approaches for setting the tab's content. The developer can:

  • Set the content of a tab to an Intent. Figures Figure 11-7 and Figure 11-9 use this method.

  • Use a TabContentFactory to create the tab's content on-the-fly. Figure 11-8 uses this method.

  • Retrieve the content from an XML layout file, much like that of a regular Activity. Figure 11-10 uses this method.

We'll examine each of these possibilities using a modified Activity from the ApiDemos application. The fourth tab is not part of the ApiDemos, but combines some other TabHost demonstration Activities in ApiDemos.

Let's start by looking at the tabs4.xml layout file (Example 11-7).

Example 11-7. Layout file for TabHost (tabs4.xml)

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView android:id="@+id/view4"
        android:background="@drawable/green"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="@string/tabs_4_tab_4"/>

</FrameLayout>

Here are some of the highlights of the code:

And now we'll dissect the Java code that produces the tabs (Example 11-8).

Example 11-8. Java for TabHost

public class Tabs4 extends TabActivity implements TabHost.TabContentFactory {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final TabHost tabHost = getTabHost();

        LayoutInflater.from(this).inflate(R.layout.tabs4, tabHost.getTabContentView(), 
          true);

        tabHost.addTab(tabHost.newTabSpec("tab1")
                .setIndicator("intent")
                .setContent(new Intent(this, List1.class)));

        tabHost.addTab(tabHost.newTabSpec("tab2")
                .setIndicator("factory", 
                  getResources().getDrawable(R.drawable.star_big_on))
                .setContent(this));

        tabHost.addTab(tabHost.newTabSpec("tab3")
                .setIndicator("destroy")
                .setContent(new Intent(this, Controls2.class)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)));

        tabHost.addTab(tabHost.newTabSpec("tab4")
                .setIndicator("layout")
                .setContent(R.id.view4));
    }

    public View createTabContent(String tag) {
        final TextView tv = new TextView(this);
        tv.setText("Content for tab with tag " + tag);
        return tv;
    }
}

Here are some of the highlights of the code:

          
      Previous section   Next section