Android Logo MathCS.org - Android

View Groups, Lists and More

java -> android -> view groups, lists, and more ...

In this segment we will move to more complex views: view groups that not only layout and organize their child views or widgets but also provide additional functionality. In other words:

Frequently used classes that are considered complex views are:

These views use an "adapter" as storage for its elements (more soon). Other complex views are:

Adapter Views: Gallery, GridView, ListView

As we mentioned, Gallery, GridView, and ListView display data from a data source bound to their view via an Adapter. The most common adapter classes are CursorAdapter (for example for data coming from a database) and ArrayAdapter (for data stored in an array or list). Four pieces need to go together: the data, a description of how to render one data element, a view to describe the layout of the collection of items, and an adapter to mediate between the group view, the individual view, and the data.

ArrayAdapter

To see how everything fits together, create a new Android 1.5 project named FirstAdapt. Goto the layout folder inside the res folder. Highlight the main.xml file, select "Edit | Copy", then paste it into the same folder, but ame the copy dataview.xml. Open the copied file dataview.xml, delete all views it contains, then add a single TextView with id = @+id/TextView, Layout width = fill_parent, Layout height = wrap_content, Text size = 20sp and nothing as Text. Save your file.

Next, open main.xml and add a ListView after the existing TextView inside the LinearLayout. Set parameters Layout width and height to fill_parent and choose as Id @+id/ListView. Save your work. The two XML files, when you look at their source, should look like this (the properties might be ordered differently in your version):

dataview.xml

<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
          android:layout_height="wrap_content" 
          android:layout_width="fill_parent" 
          android:textSize="20sp"
          android:id="@+id/TextView">
</TextView>

main.xml

<?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"
    >
    <TextView android:layout_width="fill_parent" 
              android:layout_height="wrap_content" 
              android:text="@string/hello"
     />
     <ListView android:id="@+id/ListView" 
               android:layout_height="fill_parent" 
               android:layout_width="fill_parent">
     </ListView>
</LinearLayout>

Now you have all the UI elements needed to render your data - but you still need to create your data, the adapter, initialize the views, and link everything up. So, open the source code file FirstAdapt.java and enter the following code:

public class FirstAdapt extends Activity 
{
	// define the data as an array of Strings
	private String items[] = {"Item 1", "Item 2", "Item 3", "Item 4"};
	// define  adapter and view as fields to be initialized later
	private ListView list = null;
	private ArrayAdapter<String> adapter = null;
	
	public void onCreate(Bundle savedInstanceState) 
	{
	        super.onCreate(savedInstanceState);
        	setContentView(R.layout.main);
    
	        // initialize the adapter with the ListView defined in dataview.xml
        	// and the array of String items defined in code
	        adapter = new ArrayAdapter<String>(this, R.layout.dataview, items);
 
	        // initializing the list from main.xml
        	list = (ListView) this.findViewById(R.id.ListView);
	        // getting the list view to use this adapter
        	list.setAdapter(adapter);        
	}
}

The remaining two adapter-based views are Gallery and GridView - but they can use the same adapter and data! Same data (and adapter) but different views of the data!

Let's represent the data as a grid: Open main.xml, remove the ListView and add instead a GridView. Set its Id to @+id/GridView, the Layout width and height to fill_parent, and the Num columns to 2. Now replace all references to "list view" in the source code by a "grid view" and run the app again, without changing the data or the adapter.

Finally, we can replace the GidView by a Gallery in main.xml, change the source code accordingly, and we can view the data as a gallery of horizontally scrolling elements. Note that the items can scroll horizontally, but each item takes up the whole width of the screen, because the TextView in dataview.xml used to render one item still has Layout width set to fill_parent. Change that Layout width to 100sp and run the app again to see everything look pretty nice.

Array data with ListView array data with grid view array data in gallery view
list view grid view gallery view

Dynamic Lists and ListEvents

In the above example the elements in the list did not change - the list was static. In a dynamic list on the other hand items can be added or removed from the list at runtime. To implement a dynamic list you can not (or should not) use an array of items, since an array has a fixed size. Instead you can use one of the Java list structures such as an ArrayList or a Vector. Much of the rest of the programming is similar to before, but you need to notify the ListView whenever a change in the list data occurs so that it can update its view.

Dynamic list exampleWhile we are at it, we are also including some coding example for how to handle list-selection evens. We'll show a program that:

We should really also include a method to delete items from the list, but we'll postpone that to the next segment on dialogs and menus.

 First, create a new project named FirstAdaptDynamic and layout a title, an input field, a button, and a list view as shown. Also create a new XML file to describe a TextView as template for the list elements, just as we did above. For your reference, the XML files are listed below.

main.xml

<?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">

	<TextView android:id="@+id/TitleView"
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:text="Dynamic List Example" 
	    android:textSize="24sp" 
	    android:textStyle="bold" 
	    android:gravity="center">
	</TextView>

	<TableLayout android:id="@+id/TableLayout01" 
		android:layout_height="wrap_content" 
		android:layout_width="fill_parent"
		android:stretchColumns="0">
		<TableRow android:id="@+id/TableRow01" 
			android:layout_height="wrap_content" 
			android:layout_width="fill_parent">

			<EditText android:id="@+id/AddField" 
				android:layout_height="wrap_content" 
				android:layout_width="wrap_content">
			</EditText>

			<Button android:id="@+id/AddButton"
				android:layout_width="wrap_content" 
				android:layout_height="wrap_content" 
				android:text="Add">
			</Button>
		</TableRow>
	</TableLayout>
	
	<ListView android:id="@+id/ListView" 
		android:layout_height="fill_parent" 
		android:layout_width="fill_parent">
	</ListView>
</LinearLayout>

dataview.xml

<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
	android:id="@+id/ListItemView" 
	android:layout_width="wrap_content" 
	android:layout_height="wrap_content"  
	android:textSize="20sp">
</TextView>
Exercise: To improve the look of our program, define a color named "blue" with value #0000cc in the strings.xml resource file. Then change the background property of the main layout in main.xml and the text view in dataview.xml to refer to that color.

With the layout defined, let's go to the source code. First, we create a program similar to beore but with an ArrayList instead of an array to store the list items.

public class FirstAdaptDynamic extends Activity 
{
	// define the data as an array of Strings
	private ArrayList<String> items = new ArrayList<String>();
	// define  adapter and view as fields to be initialized later
	private ListView list = null;
	private ArrayAdapter<String> adapter = null;
	
    	public void onCreate(Bundle savedInstanceState) 
    	{
        	super.onCreate(savedInstanceState);
	        setContentView(R.layout.main);

	        // add some items to the adapter
        	items.add("John Dear");
       		items.add("Jane Doe");
        
        	// initialize the adapter with the ListView defined in dataview.xml
        	// and the array of String items defined in code
        	adapter = new ArrayAdapter<String>(this, R.layout.dataview, items);
 
        	// initializing the list from main.xml
        	list = (ListView) this.findViewById(R.id.ListView);
        	// getting the list view to use this adapter
        	list.setAdapter(adapter);        
    	}
}

That creates an app with a static list as before. To enable the button to add the content of the text field:

	// define the add button and field
	private Button addButton = null;
	private EditText addField = null;
	// define the button handler
	private class AddHandler implements View.OnClickListener
	{
		public void onClick(View v)
		{
			String newItem = addField.getText().toString();
			items.add(newItem);
			adapter.notifyDataSetChanged();
		}
	}
         // attaching the listeners
        addButton.setOnClickListener(new AddHandler());

Now we can add items to the list. Note that the list will automatically get scrollbars when necessary. There are a few improvements possible, all left to you:

Last, we define a handler to listen to "list selection events". If it notices one it will display the position of the item that was clicked by the user. The principle is the same as for buttons: define a handler class and attach it to the element whose events to intercept:

	// define the list selection handler
	private class ListItemSelectedHandler implements AdapterView.OnItemClickListener
	{
		public void onItemClick(AdapterView<?> adapt, View view, int position, long id)
		{
			Toast.makeText(FirstAdaptDynamic.this, "Selected item " + position, 
                                       Toast.LENGTH_SHORT).show();
		}		
	}
         // attaching the listener
        list.setOnItemClickListener(new ListItemSelectedHandler());

That should give you a pretty complete list-handling program you can experiment with. To add to the functionality of this program, we will introduce how to work with menus and dialogs next. You could already try to enhance your program to handling "long clicks" on a list item, at least by displaying the item long-clicked on.

CursorAdapter

tbc

Drop-down Lists

tbc