Using Built-In View Container Classes Android

Layouts are not the only controls that can contain other View objects. Although layouts are useful for positioning other View objects on the screen, they aren’t interactive. Now let’s talk about the other kind of ViewGroup: the containers. These View objects encapsulate other, simpler View types and give the user some interactive ability to browse the child View objects in a standard fashion. Much like layouts, these controls each have a special, well-defined purpose.

An example of multiple layouts used together.

An example of multiple layouts used together

The types of ViewGroup containers built-in to the Android SDK framework include

  • Lists, grids, and galleries
  • Switchers with ViewFlipper, ImageSwitcher, and TextSwitcher
  • Tabs with TabHost and TabControl
  • Scrolling with ScrollView and HorizontalScrollView
  • Hiding and showing content with the SlidingDrawer

Using Data-Driven Containers

Some of the View container controls are designed for displaying repetitive View objects in a particular way. Examples of this type of View container control include ListView, GridView, and GalleryView:

  • ListView: Contains a vertically scrolling, horizontally filled list of View objects, each of which typically contains a row of data; the user can choose an item to perform some action upon.
  • GridView: Contains a grid of View objects, with a specific number of columns; this container is often used with image icons; the user can choose an item to perform some action upon.
  • GalleryView: Contains a horizontally scrolling list of View objects, also often used with image icons; the user can select an item to perform some action upon.

These containers are all types of AdapterView controls. An AdapterView control contains a set of child View controls to display data from some data source. An Adapter generates these child View controls from a data source. As this is an important part of all these container controls, we talk about the Adapter objects first.

In this section, you learn how to bind data to View objects using Adapter objects. In the Android SDK, an Adapter reads data from some data source and provides a View object based on some rules, depending on the type of Adapter used. This View is used to populate the child View objects of a particular AdapterView.

The most common Adapter classes are the CursorAdapter and the ArrayAdapter. The CursorAdapter gathers data from a Cursor, whereas the ArrayAdapter gathers data from an array. A CursorAdapter is a good choice to use when using data from a database. The ArrayAdapter is a good choice to use when there is only a single column of data or when the data comes from a resource array.

There are some common elements to know about Adapter objects. When creating an Adapter, you provide a layout identifier. This layout is the template for filling in each row of data. The template you create contains identifiers for particular controls that the Adapter assigns data to. A simple layout can contain as little as a single TextView control. When making an Adapter, refer to both the layout resource and the identifier of the TextView control. The Android SDK provides some common layout resources for use in your application.

Using the ArrayAdapter

An ArrayAdapter binds each element of the array to a single View object within the layout resource. Here is an example of creating an ArrayAdapter:

In this example, we have a String array called items. This is the array used by the ArrayAdapter as the source data. We also use a layout resource, which is the View that is repeated for each item in the array. This is defined as follows:

This layout resource contains only a single TextView.However, you can use a more complex layout with the constructors that also take the resource identifier of a TextView within the layout. Each child View within the AdapterView that uses this Adapter gets one TextView instance with one of the strings from the String array.

If you have an array resource defined, you can also directly set the entries attribute for an AdapterView to the resource identifier of the array to automatically provide the Array Adapter.

Using the CursorAdapter

A CursorAdapter binds one or more columns of data to one or more View objects within the layout resource provided. This is best shown with an example. The following< example demonstrates creating a CursorAdapter by querying the Contacts content provider. The CursorAdapter requires the use of a Cursor.

In this example, we present a couple of new concepts. First, you need to know that the Cursor must contain a field named _id. In this case, we know that the Contacts content provider does have this field. This field is used later when you handle the user selecting a particular item.

We make a call to managedQuery() to get the Cursor. Then, we instantiate a Simple Cursor Adapter as a ListAdapter. Our layout, R.layout.two _text, has two TextView objects in it, which are used in the last parameter. SimpleCursorAdapter enables us to match up columns in the database with particular controls in our layout. For each row returned from the query, we get one instance of the layout within our AdapterView.

Binding Data to the AdapterView

Now that you have an Adapter object, you can apply this to one of the AdapterView controls. Any of them works. Although the Gallery technically takes a Spinner Adapter,the instantiation of SimpleCursorAdapter also returns a SpinnerAdapter. Here is an example of this with a ListView, continuing on from the previous sample code:

The call to the setAdapter() method of the AdapterView, a ListView in this case, should come after your call to setContentView(). This is all that is required to bind data to your AdapterView. Figure shows the same data in a ListView, Gallery, and GridView.

ListView, Gallery, and GridView: same data, same list item, differentlayout views.

ListView, Gallery, and Grid View: same data, same list item, different layout views

Handling Selection Events

You often use AdapterView controls to present data from which the user should select. All three of the discussed controls—ListView, GridView, and Gallery—enable your application to monitor for click events in the same way.You need to call setOnItemClickListener() on your AdapterView and pass in an implementation of the Adapter View.OnItemClickListener class. Here is an example implementation of this class:

In the preceding example, av is our AdapterView. The implementation of the onItemClick() method is where all the interesting work happens. The parent parameter is the AdapterView where the item was clicked. This is useful if your screen has more than one AdapterView on it. The View parameter is the specific View within the item that was clicked. The position is the zero-based position within the list of items that the user selects. Finally, the id parameter is the value of the _id column for the particular item that the user selects. This is useful for querying for further information about that particular row of data that the item represents.

Your application can also listen for long-click events on particular items. Additionally, your application can listen for selected items. Although the parameters are the same, your application receives a call as the highlighted item changes. This can be in response to the user scrolling with the arrow keys and not selecting an item for action.

Using the ListActivity

The ListView control is commonly used for full-screen menus or lists of items from which a user selects. As such, you might consider using ListActivity as the base class for such screens. Using the ListActivity can simplify these types of screens.

First, to handle item events, you now need to provide an implementation in your List Activity. For instance, the equivalent of onListItem Click Listener is to implement the onListItemClick() method within your ListActivity.

Second, to assign an Adapter, you need a call to the setListAdapter() method. You do this after the call to the setContentView() method. However, this hints at some of the limitations of using ListActivity.

To use ListActivity, the layout that is set with the setContentView() method must contain a ListView with the identifier set to android:list; this cannot be changed. Second, you can also have a View with an identifier set to android:empty to have a View display when no data is returned from the Adapter. Finally, this works only with ListView controls, so it has limited use. However, when it does work for your application, it can save on some coding.

Organizing Screens with Tabs

The Android SDK has a flexible way to provide a tab interface to the user. Much like ListView and ListActivity, there are two ways to create tabbing on the Android platform. You can either use the TabActivity, which simplifies a screen with tabs, or you can create your own tabbed screens from scratch. Both methods rely on the TabHost control.

Using TabActivity

A screen layout with tabs consists of a TabActivity and a TabHost. The TabHost consists of TabSpecs, a nested class of TabHost, which contains the tab information including the tab title and the contents of the tab. The contents of the tab can either be a predefined View, an Activity launched through an Intent object, or the View can be created with a factory provided by an implementation of TabContentFactory.

Tabs aren’t as complex as they might sound at first. Each tab is effectively a container for a View. That View can come from any View that is ready to be shown, such as an XML layout file. Alternatively, that View can come from launching an Activity. The following example demonstrates each of these methods using View objects and Activity objects created in the previous examples of this chapter:

This example creates a tabbed layout view with four tabs on it, as shown in Figure. The first tab is from the recent GridView sample. The second tab is from the ListView sample before that. The third tab is the basic layout with two TextView objects, fully defined in an XML layout file as previously demonstrated. Finally, the fourth tab is created with a factory.

Four tabs displayed.

Four tabs displayed

The first action is to get the TabHost instance. This is the object that enables us to add Intent objects and View identifiers for drawing the screen. A TabActivity provides a method to retrieve the current TabHost object.

The next action is only loosely related to tab views. The LayoutInflater is used to turn the XML definition of a View into the actual View objects. This would normally happen when calling setContentView(), but we’re not doing that. The use of the LayoutInflater is required for referencing the View objects by identifier, as is done for the third tab.

The code finishes up by adding each of the four tabs to the TabHost in the order that they will be presented. This is accomplished by multiple calls to the addTab() method of TabHost. The first two calls are essentially the same. Each one creates a new Intent with the name of an Activity that launches within the tab. These are the same Activity classes used previously for full-screen display. If the Activity isn’t designed for full-screen use, this should work seamlessly.

Next, on the third tab, a layout View is added using its identifier. In the preceding call to the LayoutInflater, the layout file also contains an identifier matching the one used here at the top level of a LinearLayout definition. This is the same one used previously to show a basic LinearLayout example. Again, there was no need to change anything in this view for it to display correctly in a tab.

Next, a tab referencing the content as the TabActivity class is added. This is possible because the class itself also implements TabHost.TabContentFactory, which requires implementing the createTabContent() method. The view is created the first time the user selects the tab, so no other information is needed here. The tag that creates this tab must be kept track of, though, as that’s how the tabs are identified to the TabHost.

Finally, the method createTabContent() is implemented for use with the fourth tab. The first task here is to check the tag to see if it’s the one kept track of for the fourth tab. When that is confirmed, an instance of the TextView object is created and a text string assigned to it, which contains the current time. The size of the text is set to 24 pixels. The time stamp used in this string can be used to demonstrate when the view is created and that it’s not re-created by simply changing tabs.

The flexibility of tabs that Android provides is great for adding navigation to an application that has a bunch of views already defined. Few changes, if any, need to be made to existing View and Activity objects for them to work within the context of a TabHost.

Implementing Tabbing Without TabActivity

It is possible to design tabbed layouts without using the TabActivity class. However, this requires a bit of knowledge about the underpinnings of the TabHost and TabWidget controls. To define a set of tabs within an XML layout file without using TabActivity, begin with a TabHost (for example, TabHost1). Inside the TabHost, include a vertically oriented LinearLayout that must contain a TabWidget (which must have the id @android:id/tabs) and a FrameLayout (which must have id @android :id /tabcontent). The contents of each tab are then defined within the FrameLayout.

After you’ve defined the TabHost properly in XML, you must load and initialize it using the TabHost setup() method on your activity’s onCreate() method. First, you need to create a TabSpec for each tab, setting the tab indicator using the setIndicator() method and the tab content using the setContent() method. Next, add each tab using the addTab() method of the TabHost. Finally, you should set the default tab of the TabHost, using a method such as setCurrentTabByTag().

Adding Scrolling Support

One of the easiest ways to provide vertical scrolling for a screen is by using the ScrollView (vertical scrolling) and HorizontalScrollView (horizontal scrolling) controls. Either control can be used as a wrapper container, causing all child View controls to have one continuous scrollbar. The ScrollView and HorizontalScrollView controls can have only one child, though, so it’s customary to have that child be a layout, such as a LinearLayout, which then contains all the “real” child controls to be scrolled through. Figure shows a screen with and without a ScrollView control.

A screen with (right) and without (left) a ScrollView control.

A screen with (right) and without (left) a Scroll View control

Exploring Other View Containers

Many other user interface controls are available within the Android SDK. Some of these controls are listed here:

  • Switchers: A ViewSwitcher control contains only two child View objects and only one of those is shown at a time. It switches between the two, animating as it does so. Primarily, the ImageSwitcher, shown in Figure, and TextSwitcher objects are used. Each one provides a way to set a new child View, either a Drawable resource or a text string, and then animates from what is displayed to the new contents.
  • ImageSwitcher while in the middle of switching between two Drawable resources.

    ImageSwitcher while in the middle of switching between two Drawable resources.

  • SlidingDrawer: Another View container is the SlidingDrawer control. This control includes two parts: a handle and a container view. The user drags the handle open and the internal contents are shown; then the user can drag the handle shut and the content disappears. The SlidingDrawer can be used horizontally or vertically and is always used from within a layout representing the larger screen. This makes the SlidingDrawer especially useful for application configurations such as game controls. A user can pull out the drawer, pause the game, change some features, and then close the SlidingDrawer to resume the game. Figure shows how the typical SlidingDrawer looks when pulled open.

SlidingDrawer sliding open to show contents.

SlidingDrawer sliding open to show contents.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd Protection Status

Android Topics