Thursday, July 7, 2011

Adding an Arrow Image to the Right of a ListView

The following shows how to create a ListView with an arrow image to the right of the text for a simple application in Android. It also shows how to create a class to handle adapting the text and images to the ListView in a reusable way.

The motivation behind the application is to highlight how an array of text strings and an array of boolean values can be passed to an adapter that binds this information to a ListView and to show the strings in the array as list items, as well as showing how a right-arrow on the right side of the list based on the values in the boolean array can be produced.


Creating the Layout

The ListActivity class is used instead of the Activity class so that the extended methods of the ListActivity class can be accessed, in particular the setListAdpater() method that makes the task of setting the adapter for the ListView in our layout easier to perform.

In the main.xml, the layout consists of a RelativeLayout that surrounds a ListView, a TextView, and and an ImageView.

As the ListActivity is being used in our example, the ListView is required in the layout with an id of ‘list’ to prevent a NullPointerException when setContentView() is called.

The TextView is the element that will display the text from our string array for each element. To make this align to the left of the RelativeLayout, the property android:layout_alignParentLeft="true" is set.

The ImageView is the element that will contain the right-arrow image that we want to set. To make this align to the right of the RelativeLayout, the property android:layout_alignParentRight="true" is set.

The main.xml appears below:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/layercontainer"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:background="#ffffff">
   <ListView 
   android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>
   <TextView
    android:id="@+id/text1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true" 
    android:padding="10dp"
    android:textSize="16sp"
    android:textColor="#000000"    
    android:typeface="sans"/>
   <ImageView
    android:id="@+id/image1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"/>
</RelativeLayout>


Creating the Adapter

The ImageAdapter class is a standalone class (as opposed to a nested class in the ListActivity) that binds the text and boolean arrow information to the ListView at runtime. It extends the ArrayAdapter class and implements the getView() method to do the binding. The getView() method iterates for the number of items that are passed to the base class by the items variable through the call to super(). As ImageAdapter is not nested in the ListActivity, all required variables are passed through the class' constructor. This includes the arrays, the activity context and the id’s of the TextView and ImageView that are to be bound to. This also allows the class to be reusable for multiple ListViews.

Within the getView() method,  the currently selected row is inflated from the layout through the inflate() method, which returns a View to the current row that is to be manipulated.

The call to setText() assigns the string array for the row position to the current row’s TextView.
Based on the current row and the corresponding boolean array, if the array element is true, the ImageView for the row is retrieved with findViewById() and the arrow image is assigned to it with the setImageResource() method. The arrow image is stored in the ‘\res\drawable’ location of the project as an image called arrow.jpg and is called as R.drawable.arrow.

The code for the ImageAdapter class is shown below:

package com.ListViewApp;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ImageAdapter extends ArrayAdapter 
{ 
    Activity context;
    String[] items;
    boolean[] arrows;
    int layoutId;
    int textId;
    int imageId;

    ImageAdapter(Activity context, int layoutId, int textId, int imageId, String[] items, boolean[] arrows) 
    { 
        super(context, layoutId, items); 

        this.context = context; 
        this.items = items;
        this.arrows = arrows;
        this.layoutId = layoutId;
        this.textId = textId;
        this.imageId = imageId;
    } 

    public View getView(int pos, View convertView, ViewGroup parent) 
    { 
        LayoutInflater inflater=context.getLayoutInflater(); 
        View row=inflater.inflate(layoutId, null); 
        TextView label=(TextView)row.findViewById(textId); 

        label.setText(items[pos]); 
        
        if (arrows[pos]) 
        { 
         ImageView icon=(ImageView)row.findViewById(imageId);  
            icon.setImageResource(R.drawable.arrow); 
        }    

        return(row); 
    } 
} 

The Main ListActivity

The main call to the application is through the ListActivity class that basically sets the content of the View for the current Activity and sets the custom ImageAdapter for the list in the current Activity. The code for this is shown below:

package com.ListViewApp;

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

public class ListViewActivity extends ListActivity 
{
 String[] listItems={"alpha", "beta", "gamma", "delta", "epsilon"}; 
 boolean[] listImages={true, false, true, false, true};
 
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setListAdapter(new ImageAdapter(this, R.layout.main, R.id.text1, R.id.image1, listItems, listImages ));
        
    }
}


The complete project can be downloaded from here.

6 comments:

  1. Cool - thanks for sharing

    ReplyDelete
  2. Very nice tutorial. Thanks a lot :)

    ReplyDelete
  3. Hi I want to show two separate list view with separate labels on the top of two list.Could you please provide any solution...

    ReplyDelete
  4. thank you for sharing it is helpful

    ReplyDelete