Sunday, July 12, 2009

A Custom ListView for Android

I have been thinking about starting a new blog for Android stuff for quite a long time. And today, I found some time for the same. So here goes my first post. This is about developing your own custom list view. The List View is a very powerful UI element for the android platform. And it provides a lot of customizing features as well. Let’s jump into the details right away.
For this example, I will be using an example for a phone book entry, with the contacts having basic information like “name”, “phone” and “email”.

Step 1: Lets create a POJO class for the phone book.
Class name : Phonebook.java
Not a complex code. Just the three fields, a constructor and the getters and setters. That’s it.
Step 2: Lets create the layout that each row of the List View is going to look like. I prefer to do this layout in xml rather than through coding/programmatically. xml stuff is pretty easy to develop.
File name : phone_row.xml 

This layout has three Text Views, tvContact, tvMobile and tvMail which we will be using in our code. We don’t need to touch any other elements from this file, if you should have to edit this xml, do it carefully.

Step 3: Now, lets create a class which our custom adapter will be calling to render each row of the List View. Here, we need the layout file created in Step 2. This class should extend any layout type, e.g, LinearLayout, TableLayout, etc. In my example, I am using a LinearLayout.

Class name : PhonebookAdapterView.java
In this class, create a constructor with two parameters, Context and the Pojo class Phonebook. And, inside the constructor, set the fields to the text views. The “this.setTag(entry)” will enable us to get info on the phonebook entry, when we use the listener for List View.

Update: I have deleted this class from the example, and have used the efficient way recommended for ListView. Checkout out the code.

Step 4: Now, create the Phonebook adapter class which extends the BaseAdapter. This will be used to set a list of Phonebook items to the list view with our customized layout.

Class name : PhonebookAdapter.java
This class has a bit of coding, and changes to be made in the default methods that comes in when you extend the BaseAdapter class, however it is simple enough. A new constructor and two new private members is all that you have to include.
Custom List ViewOverride the methods as given in the code. The method getView is the important one. Here, we call our PhonebookAdapterView class.

Now, you are done. Your custom list view has been created. The final step would be testing the custom list view. Just create and activity with a listview. Then create an instance of the PhonebookAdapter class passing the parameters (Context and list of Phonebook objects)

Then, set this adapter to the list view. You are done. Here is the output.
Here is the link where you can find all the source code as an Android Project (1.5 compatible).

 Full source code is here.

Update: I have updated the example, to include a button on each line item, which when clicked, removes that item from the List View.



92 comments:

  1. That is a fantastic bit of code right there! Thank you so much for making something so clean and useful.

    ReplyDelete
  2. how to check for list items selected ?

    ReplyDelete
  3. You will have to write a Listener.

    On the ListView, you have a method called setOnItemClickListener. That should help you.

    ReplyDelete
  4. setOnItemClickListener method takes a listener object as a parameter. Should i have to implement a listener class?
    if so, how?

    ReplyDelete
  5. this method requires a listener object as parameter. do i have to implement listener class?

    ReplyDelete
  6. Yes, you will need to . Else, you can create an anonymous class as well. Like this.

    listView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView arg0, View arg1, int arg2,long arg3) {

    // TODO Auto-generated method stub

    }
    });

    ReplyDelete
  7. Hi Kumar,

    Thanks for your custom listview code. I am struggling with consuming webservice and display in listview.. please guide me.

    Looking forward .....

    Thanks
    Rajalakshmi

    ReplyDelete
  8. What are you looking for exactly?

    ReplyDelete
  9. Hey Kumar ....

    i want to implement a list view like the one that appears when we click on "MENU" button of the device. how is it possible?

    ReplyDelete
  10. That is not a ListView control. Please let me know your exact requirements may be some screen-shots would help

    ReplyDelete
  11. i dont know how to paste the screen shot in this comment window?

    ReplyDelete
  12. You can send me a mail coomar.101(at)gmail.com

    ReplyDelete
  13. Hi Kumar,

    I am having SOAP service, needs to call and display the results in list view.
    Is it possible? please help me.

    Thanks

    ReplyDelete
  14. please check out your email

    ReplyDelete
  15. YEs, of course, it's possible. But, on Android, you will have to include a library for SOAP. Check out ksoap. And look for examples.

    ReplyDelete
  16. I tried some examples but unable to fix it. I am new to android. please help me.

    ReplyDelete
  17. Can you send me the details about the webservice so that I can send you some code.

    Mail the details to coomar.101(at)gmail.com

    ReplyDelete
  18. Hi Kumar,

    In sqlite ,the Delete/Update methods are not working. I used correct Query muDB.execSQL("DELETE FROM " + TABLE_NAME);.

    ReplyDelete
  19. What error are you getting? Can you post some code??

    I am sure that they do work. You must be doing something wrong.

    ReplyDelete
  20. How to store SAXParser data into sqlite table.

    ReplyDelete
  21. Any idea store SAXParser data into sqlite table

    ReplyDelete
  22. <3 wonderful example! Thank you!

    ReplyDelete
  23. hi,could you please give me the xml layout file
    abdulraqeeb33 at gmail dot com

    ReplyDelete
  24. Hi Kumar,

    Thanks for the amazing tutorial. Dude, I wish to transfer data from the phone to a webserver. I have used bare sockets earlier but want to learn how to do the same with httpurlconnection or any other better way than that. Could you please help me out in that. Thanks in advance!!!

    ReplyDelete
  25. Great tutorial! Thanks a lot! But, I've having some problems with onListItemClick method on ListActivity when I put Checkbox on row layout. Do you know what's hapening?

    ReplyDelete
  26. hi kumar..i am unable to capture the items that are clicked..i basically want all the items that are checked by the user, maybe in an array or something... i tried doing this

    list.setOnItemClickListener(this);



    @Override
    public void onItemClick(AdapterView arg0, View arg1, int arg2,
    long arg3) {
    pos[i++]=arg3;

    }
    I thought of using the pos array later. But the program quits.. could you please let me know what needs to be done...

    ReplyDelete
  27. well.. i fixed the issue..thanks

    ReplyDelete
  28. Hi Kumar,
    When i set the listview child view Background, the default listview focus is not visible. How do make default focus visible ?...

    ReplyDelete
  29. Try using StateDrawables since you are overriding the default background. But, without some code examples, I might not be able to tell you exactly what to do.

    ReplyDelete
  30. can i have ur code plzz i need it

    ReplyDelete
  31. wonderful example .. looking forward to more tutorials

    ReplyDelete
  32. Great example! Thanks for this.

    ReplyDelete
  33. its what i am looking for... thank you soo much, you rock...

    ReplyDelete
  34. it's a great tutorial , Thanks man !!

    ReplyDelete
  35. hi i would to like to place a delete button in listview.... if i press that the full row must be deleted and listadpter must be refreshed.....


    Pls help me.... As early as possible.... Urgent....

    ReplyDelete
  36. Sure it's possible, I will alter this code to do just this. This will be a nice example

    ReplyDelete
  37. @Anonymous, you can check the code now. You will find a button in the phone_row.xml which handles removal of the items.

    ReplyDelete
  38. Hi Thank you very much for your code.....

    ReplyDelete
  39. Thanks for your post! I was a big help.

    ReplyDelete
  40. how can i add a separator in a list like for example cars heading separator with the list of cars underneath it than ships separator with the list of ships available and so on.

    ReplyDelete
  41. hi kumar,
    i have created a list view to display more items. but i have a problem while clicking the items to display the descrtiption page.In onitemclicklistener i have start intent to display that page. can you send me a code.

    ReplyDelete
  42. hello kumar

    nice post, thank a lot.

    but I have some problem to display my own textview like you. I would like to know where the function getview is used.

    thank

    ReplyDelete
  43. I'm always getting this Error, running your example
    02-24 09:41:33.547: ERROR/AndroidRuntime(3293): Caused by: java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView

    ReplyDelete
  44. friend tell me how i display contact photo in custom list view

    ReplyDelete
  45. What exactly do you mean by contact photo? If you have the link to the image file, you can set the image source to this file. Are you getting any errors?

    ReplyDelete
  46. Hi Kumar,
    a REALLY great Tutorial. I have a request pls. I am trying to start another activity when a user clicks on one of the ListView elements, but from within the Adaptor class - something like:

    public void onClick(View view) {
    InfoBook entry = (InfoBook) view.getTag();
    int id = listInfoBook.indexOf(entry);
    InfoBook iBook = (InfoBook) this.getItem(id);
    Intent myIntent = new Intent(view.getContext(), SpeciesSubset.class);
    Bundle b = new Bundle();
    b.putString("RING", iBook.getRing());
    myIntent.putExtras(b);
    startActivityForResult(myIntent, 0);
    }

    But it doesn't recognise startActivityForResult. I have tried using the

    listView.setOnItemClickListener(new OnItemClickListener()

    approach from within the main view, but I can't get it to read the view properly - it says I'm loking at a LinearLayout!
    Any suggestions.
    Thanks
    Iain

    ReplyDelete
  47. Actually, just sorted it by using:

    context.startActivity(myIntent);

    Sorry, was being really stupid.
    Thanks for the good work.
    Iain

    ReplyDelete
  48. Great work! This actually worked better than me using a Custom Adapter and extending the ListActivity.

    Using your example I was able to have multiple list views that are inside a different activity yet still have customized ListViews!

    Thanks,
    Kevin

    ReplyDelete
  49. Great article and code!
    Thanks for sharing it :)

    ReplyDelete
  50. Hi,

    I’m new to android development. I’m working on an application that have a list view. Each row has 3 images. I need to know which image in the row is clicked.
    The code implements:
    private OnItemClickListener gridView_OnItemClickListener = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View view, int position, long id) {

    }
    }
    How inside onItemClick can I know which image was clicked?

    Thanks,
    Ronny

    ReplyDelete
  51. Well, @Ronny, For this situation, you cant do that using the onItemClick listener, rather you have to set corresponding listeners to your image views.

    ReplyDelete
  52. This is great. The problem I'm running into though is this error: ERROR/ArrayAdapter(1007): You must supply a resource ID for a TextView

    It doesn't make sense to me since the custom adapter is extending BaseAdapter, not ArrayAdapter. This seems to happen when the adapter is set on the listview. Also, this wasn't happening when there was a just a textView in the xml. It only started happening when I started trying to wrap it into a LinearView.
    Thoughts?

    ReplyDelete
  53. Strange..I would need to look at the code to check what's wrong.

    ReplyDelete
  54. Never mind. I realized that I had 2 other listviews that were using some old setAdapter code to ArrayAdapters. So, my issue was completely unrelated. But thanks for getting back so soon. Great tutorial!

    ReplyDelete
  55. Hi again, I am using your code above heavily, so again thanks for putting online. Question: since using the AdapterClass within the list view, I have lost the ability to keyboard search. Is this possible through any other route?
    Iain

    ReplyDelete
  56. Keyboard search meaning when viewing the simple ListView (no adapter involved), long hold the menu button on the phone (Desire) brings up the keyboard, I start typing and the listview reduces to just those elements that match what you are typing.

    ReplyDelete
  57. Hmm, that's probably a feature of the app you are using. You have to do extra code for it.

    ReplyDelete
  58. This works on the emulator too - I just start typing and the ListView automatically reduces to those elements that match the typing, so it's not particular to my app or the hardware. I don't suppose you know where to start with the extra code needed for the search? Just start with Google search? I want this to be undependant of internet connection, so really just focussing on the contents of the ListView Adapter class....

    ReplyDelete
  59. GREAT GREAT GREAT PIECE OF CODE... This helped me a lot!! Thank you very much!!

    ReplyDelete
  60. Christine DauniqueMay 14, 2011 at 1:39 AM

    Thank you very much for the code! Really simple ! Just what I was looking for, with the delete button on each row !

    I've also found some stuff about the ViewHolder pattern ( http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/List14.html )
    I think it's a good way to improve the rendering in a listItem view, by avoiding to call the findViewById method for each row...
    Maybe someday you can update your code with this pattern :) ?

    ReplyDelete
  61. Thanks Christine,

    ViewHolder pattern is definitely more efficient. This example/post is meant for the simplest Custom ListView.

    I would have written another post with the ViewHolder pattern, but you could find numerous examples of it on the web. And, I am a little lazy :D

    ReplyDelete
  62. Hi, thanks for writing this up. It was very useful.

    ReplyDelete
  63. This is, without a doubt, one of the best tutorials I've found on implementing something on Android:

    Understood everything, and it does work for real!!!

    Thank you so much!!

    I might need some further help on some extension I want to do to this code, may I contact you on that said email on other comment replies?

    Thanks in advance!!

    ReplyDelete
  64. @Guille: Sure. Drop me a mail.

    ReplyDelete
  65. Hello Kumar,
    I trying to make an application to such as sending sms via handset and then converting that sms to email and vice-versa. i have come up with a design and till now i was going well. I am stuck across broadcastreciever.
    How sud i implement it because i only one to use a single broadcastreciever for multiple actions.
    For example if someone sms with apple, then i want the whole list of apples avialable and if the other sms is apple 1 info then i want to use the same broadcastreciever for fetching info of apple 1.
    Any idea

    ReplyDelete
  66. Hi Kumar

    In this you added contact manually.

    listOfPhonebook.add(new Phonebook("Test", "9981728", "test@test.com"));
    listOfPhonebook.add(new Phonebook("Test1", "1234455", "test1@test.com"));
    listOfPhonebook.add(new Phonebook("Test2", "00000", "test2@test.com"));

    Is their any possibility to get contact from device and store it in this List

    ReplyDelete
  67. @Krishna: Of course. Look at a few examples how to extract the contacts in Android.

    ReplyDelete
  68. @Kumar
    I have done that but i want store that values in list.
    It will returning ArrayList.I want this array list value to my list . I tried but the application is forcefully closing

    Please help me

    ReplyDelete
  69. How to download source code in google code ?

    ReplyDelete
  70. hi in your phone.java class you are adding listOfPhonebook with static data but if want to add dynamic data to it how could i do it?

    ReplyDelete
  71. @ghouse: In the Adapter, you can have methods that can add more phone numbers, and the list view would be updated.

    ReplyDelete
  72. Dude - thank you. I have spent probably 15 hours trying to figure this damn ListView button thing out. You are a lifesaver.

    For those who might be interested, I assigned the click handler method for the button directly in the xml attribute for the view in the layout: android:onClick="deleteButtonClickHandler". Then I created the method deleteButtonClickHandler(View v) in my Activity and used the v.getTag inside of it to get the object info stored in the individual view (through v.setTag in the Adapter - see Kumar's PhoneBookAdapter.java). That tag is the key. I had to delete the setClickable lines and set the setFocusable lines to false in the Adapter to get everything to work the way I wanted. (My activity extends ListView and I'm binding a database, not an array.)

    ReplyDelete
  73. hi,i have a doubt i am creating a listview and in i want to store data and save in server in that case shall i go for sqlite or xml for storing and how can i post to the server

    ReplyDelete
  74. hi,
    i am creating a custom listview with dynamic radiobuttons adding to radiogroup upto that i am getting what i want but when i try to select one radio button in first row then automatically first button in 5th ,9th,13 row is getting selected and when i select any button in second row then same button in 6th,8th,12th row is getting selected what i am doing wrong here and my adapter class is.


    public class InteractiveArrayAdapter extends ArrayAdapter implements OnClickListener {
    String tag = "Events";
    private final List list;
    private final Activity context;
    int li,jh;


    public InteractiveArrayAdapter(Activity context, List list) {
    super(context, R.layout.rowbuttonlayout, list);
    this.context = context;
    this.list = list;
    }

    static class ViewHolder {
    protected TextView text;
    protected CheckBox checkbox,checkbox1;
    protected RadioGroup mgroup;
    protected RadioButton mbutton;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    Log.d(tag," 3");

    View view = null;
    if (convertView == null) {
    LayoutInflater inflator = context.getLayoutInflater();
    view = inflator.inflate(R.layout.rowbuttonlayout, null);
    final ViewHolder viewHolder = new ViewHolder();
    viewHolder.text = (TextView) view.findViewById(R.id.label);


    viewHolder.mgroup = (RadioGroup) view.findViewById(R.id.radioGroup1);
    int loi=viewHolder.mgroup.getId();
    System.out.println(loi);
    final RadioButton[] mbutton=new RadioButton[5];
    for(int l=0;l<5;l++){
    mbutton[l]=new RadioButton(context);
    mbutton[l].setText("test"+l);
    mbutton[l].setOnClickListener(this);
    // viewHolder.mbutton=(RadioButton)mbutton[l];

    viewHolder.mgroup.addView(mbutton[l]);


    }


    viewHolder.mgroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
    public void onCheckedChanged(RadioGroup mRadioGroup, int checkedId) {

    for(int i=0; i<mRadioGroup.getChildCount(); i++) {

    RadioButton btn = (RadioButton) mRadioGroup.getChildAt(i);

    int t=mRadioGroup.getId();
    jh=checkedId;
    //System.out.println(jh);
    if(btn.getId() == checkedId) {
    String text = btn.getText().toString();

    li=i;
    Model element = (Model) viewHolder.mgroup.getTag();
    element.setBte(btn.getId());

    return;
    }
    }
    }
    });




    view.setTag(viewHolder);
    viewHolder.mgroup.setTag(list.get(position));


    } else {
    view = convertView;
    ((ViewHolder) view.getTag()).mgroup.setTag(list.get(position));




    }
    ViewHolder holder = (ViewHolder) view.getTag();

    holder.text.setText(list.get(position).getName());

    holder.mgroup).setChecked(list.get(position).isSelected());





    return view;

    }
    }


    public class Model {
    String tag = "Events";
    private String name;
    private boolean selected;

    int d,kp;

    public Model(String name) {
    this.name = name;
    selected = false;

    }

    public String getName() {

    return name;
    }

    public void setName(String name) {

    this.name = name;
    }

    public int isSelected() {

    return kp;
    }

    public void setSelected(boolean selected) {

    this.selected = selected;
    }
    public void setBte(int kp){

    this.kp = kp;

    }


    }

    ReplyDelete
  75. You will need to save the states of the radio buttons and track them properly.

    ReplyDelete
  76. Kumar, I have implemented a custom listview. There is one operation that I would like it to do. If I select one of the children in the listview, it opens a pop up or new activity which displays a list of available options to choose from. Then when I select the new value, it returns to the first listview and updates the values so it shows the recently selected value.

    ReplyDelete
  77. Excellent work!

    I have looking for this code for ages and finally I've got it! Thanks a lot!

    By the other hand, could I ask you a short question? I've add the option for adding elements when someone clicks a external button to the list. Simply I've declared the adapter and the arraylist as final outside the oncreate method and then in the button I add the entry to my arraylist for be able to add the last item of the arraylist to the adapter and refresh it. But this makes me a question. My arraylist is updated for the adds but not for the removes. How can I know that a row has been deleted so I can delete that item in the arraylist?

    ReplyDelete
  78. Really thx... I was searching a kind of view for more than one week. Thanks a lot...

    ReplyDelete
  79. Hi guys, i m a newbie in android.
    Im developing an application where i need to select contacts into listview along with checkbox for multiple selection. please help

    ReplyDelete
  80. check this out -
    Custom ListView with sliding view for each list/row
    http://android-coding-tuts.blogspot.in/2012/02/custom-listview-with-sliding-view-for.html

    ReplyDelete
  81. Hey Kumar your excellent man not only for the tutorial but also for the way your are answering the doudts no one else gives in this way thatnka for the tutorial it was simply excellent man

    ReplyDelete
  82. This comment has been removed by the author.

    ReplyDelete
  83. Kumar i need a help i need a listview with two textviews in it and the data for the two textviews comes from the php server can you please help me out with this.

    thanks in advance

    ReplyDelete
  84. Hi !!!!
    This is a great . I have have solved many of my problems by reading this article
    Really Great

    ReplyDelete
  85. Hi !!!!
    This is a great . I have have solved many of my problems by reading this article
    Really Great

    ReplyDelete
  86. thanks for the suggestion; that's a great site and a worthy addition

    ReplyDelete