Wednesday, 18 April 2012

Custom adapter for ListView #android beginners

PRE:You must be familiar with simple list view/spinner and simpleAdapter.
 
By default listView only accepts a simple adapter with array of strings. However listView control be customized as you wish. Take a look of various listView use cases The world of listView Google I/O.

We can add custom controls like TextViews, buttons, images etc and make them clickable individually or as a whole. The use case can be a custom class fields you want to display in single row.



To make a listView OUR listView, We need to:
  1.  Create a main xml layout file with a ListView control placed in.
  2.  Create an xml layout which will be used to display one row of the list.
  3.  Create a custom adapter class extended from baseAdapter, and overrid its getView method

So lets define our main layout main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/contactsListViewMain"
      />
        
 </LinearLayout>

 and another layout which will be used to display one row of listView, say rowitem.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/contactname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:background="@color/FloralWhite"        
        android:textColor="@color/Black"
        />
    <TextView
        android:id="@+id/contactnum"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/LightYellow"
        android:textColor="@color/Gray"
        />
</LinearLayout>


Lets say we want to display Contact Name and Number as one record in listView. A simple Contact class can be:

public class Contact {
         private String contactName;
        private String contactNum;

        Contact(String name,String num){
            this.contactName=name;
            this.contactNum=num;
        }
        public String getContactName() {
            return contactName;
        }
        public void setContactName(String contactName) {
            this.contactName = contactName;
        }

        public String getContactNum() {
            return contactNum;
        }
        public void setContactNum(String contactNum) {
            this.contactNum = contactName;
        }

}

Now the interesting part here we will bind the contact class fields with the rowitem.xml controls. Lets make OUR adapter

public class ContactAdapter extends BaseAdapter{

    Context mycontext;
    ArrayList<Contact> contactsList;
    LayoutInflater mInflater;
    
     public ContactAdapter(Context context, ArrayList<Contact> list) {
          
         this.mycontext=context;
         contactsList = list;
         mInflater = LayoutInflater.from(context);
        
     }
    
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub

        ContactViewHolder viewHolder;
        
        if(convertView==null){
        
            convertView= mInflater.inflate(R.layout.rowitem, parent,false);
            
            viewHolder= new ContactViewHolder();
            viewHolder.name= (TextView) convertView.findViewById(R.id.contactname);
            viewHolder.number=(TextView)convertView.findViewById(R.id.contactnum);
            convertView.setTag(viewHolder);
        }
        else
        {
            viewHolder=(ContactViewHolder) convertView.getTag();
        }
        
        Contact cont=(Contact) contactsList.get(position);
        
        viewHolder.name.setText(cont.getContactName());
        viewHolder.number.setText(cont.getContactNum());
        
        return convertView; 
        
    }

    
static class ContactViewHolder{
    
    TextView name;
    TextView number;
}


@Override
public int getCount() {
    // TODO Auto-generated method stub
    //return 0;
    
    return contactsList.size();
}


@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    //return null;
    return contactsList.get(position);
}


@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return position;
}
    
    
}

Note: Note that rowitem.xml is inflated in getView and these controls are populated with the contact object's fields. We can place as many controls in rowitem.xml and in any order/layout we want and bind them with our custom object's fields.


Next we just need to create a list of custom objects [Contact] and create our adapter and set this adapter to listView. Lets say we want to display list on our starting Activity's onCreate method:

 setContentView(R.layout.main);

///creating a sample list of contacts with name and number
 ArrayList<Contact> list = new ArrayList<Contact>();
  list.add(new Contact("sohail", "11111"));
  list.add(new Contact("aziz", "122222"));
  list.add(new Contact("hassan", "33333333"));

//listView control
ListView mylistview= (ListView)findViewById(R.id.contactsListViewMain);

//here we are creating our custom adapter defined above
ContactAdapter contadapter= new ContactAdapter(this, list);

//setting listView adapter
mylistview.setAdapter(contadapter);


Thats it! One row of listView will show two items , name and number. You can change their font, color, style, alignment etc.


Download complete source contactEmail.


 Is it helpful ? Your feedback is welcomed.

2 comments:

  1. Nice tut..Sohail can you guide me how Can I dynamically populate ListView with Contact Name and Number from local phone book?

    ReplyDelete
  2. you need to get contact details from contact content provider in cursor and then populate listview using cursor adapter.

    ReplyDelete