May 222011
 

Today I’m going to go step by step through an example of using a ListView, and customizing the visual layout of items within. ListView is one of the primary UI components in the Android SDK. Its a great tool, providing you with scrolling lists and selection functionality right out of the box. With very little code, you can have a ListView displaying a list of objects for you. Just toss something like



android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:id="@+id/ListViewId"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

in your layout file (e.g. main.xml, for a simple application), and something like


setContentView(R.layout.main);

String[] items = {"red", "blue","green"};

ListView listView = (ListView) findViewById(R.id.ListViewId);
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));

on the java side in your onCreate() method. Easy, huh? Running this application will produce the following:

Now, the default ListView style in android is fine…until you need more than a snippet of text displayed for each item. It happens to us all. Luckily, when this time comes, the Android API is nicely prepared. Just a few tweaks, and you can have a ListView with items showing images, a couple lines of text, whatever your heart desires. And I’m going to show you how. Let’s start with the simple example from above. Let’s say we want to make our list display users of our app, instead of colors. For each user, we’d like to display username, email address, and an avatar. But how do we configure the ListView to display this content, and how do we set the layout? First, let’s set the layout we’d like for our ListView items. To keep things orderly, create a new file in the layouts directory called listitem.xml. Put the following code in listitem.xml:



android:layout_height="wrap_content"
android:gravity="left|center"
android:layout_width="wrap_content"
android:paddingBottom="5px"
android:paddingTop="5px"
android:paddingLeft="5px">

android:id="@+id/avatar"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6dip"
android:src="@drawable/icon" />
android:orientation="vertical"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent">

<TextView android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10px"
android:textColor="#0099CC"/>


This may look a bit complicated, but its really not. This xml will just define the layout of our items, so each selection in the ListView will have this layout within it. We’ve created a linear layout as our root layout (note: since we didn’t specify, this layout will have a horizontal orientation for components inside of it). Inside of this base structure, we have two sub-components: an ImageView, which will display a single image, and a LinearLayout components with a vertical orientation. In this inner LinearLayout, we have two TextView components. This will display two text fields, one on top of the other, horizontally adjacent to the ImageView. Take a look at the ImageView definition. We have to tell the ImageView what image it will display. We tell it this with the android:src parameter. For simplicity, we are giving this a value of “@drawable/icon”, which will tell it to use a file named icon.* (any image extension) found in one of the “res/drawable-*” directories. This icon file is included in any new android project created through eclipse, making it an easy target – you could just as easily point it at any image file you chose to put in these directories. In a real application to display user avatars, we would want to change this value in our java code to place a different avatar image in each ListView item. Now we just have to create a new Adapter class that will tell our ListView how to user this new item layout. To make things easier, I’ll first create a small UserRecord class to allow us to pass our user item data around easily. Here it is:


public class UserRecord {
public String username;
public String email;

public UserRecord(String username, String email) {
this.username = username;
this.email = email;
}
}

Now for the adapter, which is a bit more complex:


public class UserItemAdapter extends ArrayAdapter<UserRecord> {
private ArrayList<UserRecord> users;

public UserItemAdapter(Context context, int textViewResourceId, ArrayList<UserRecord> users) {
super(context, textViewResourceId, users);
this.users = users;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.listitem, null);
}

UserRecord user = users.get(position);
if (user != null) {
TextView username = (TextView) v.findViewById(R.id.username);
TextView email = (TextView) v.findViewById(R.id.email);

if (username != null) {
username.setText(user.username);
}

if(email != null) {
email.setText("Email: " + user.email );
}
}
return v;
}
}

So what are we doing here? Let’s take a look. We are creating an adapter class which extends ArrayAdapter, meaning this adapter will take an array of UserRecord objects as input. In the constructor, we just call the superclass constructor to handle any background initialization issues that we don’t want to worry about, and take the list of UserRecords given as an input parameter and save it to a local variable for safekeeping. The main thing we are doing here is overriding the getView() method with our own version – this will allow us to specify how to set the values of the UI components ourselves, since we are the ones who created this UI layout. When our app is displaying a ListView, it will call getView() for each item in the input array. getView() takes three parameters:

  • int position – the position of the item in the array we want to display
  • a View – the view that will display the item in question
  • a ViewGroup parent – the group our view belongs to. We won’t need to deal with this for the task at hand. We do a little handling at the top in case the View object passed in is null (it shouldn’t be in this example), and then we can set some values. Since we grabbed the list of UserRecord objects and stored it in a member variable in the UserItemAdapter constructor, we just get the objects at the specified position to have access to all of the values we want (just username and email, here, but obviously it could be much more data). Using a few findViewById() calls on our View, we get the UI components (TextView objects, in this case) that we want to use to displat our data, and set their text values using the specified UserRecord object. Return the View, and viola! Our ListView now looks like:

Remember that we specified the image to be displayed in our layout XML file, so each item has the same image. If we wanted a different avatar image for each user, we would just store some more data in our UserRecord objects and set the source image for the ImageView object in the same manner as for the TextViews. Thanks for reading! Below are some links to download source files for today’s example. Stay tuned for more future posts illustrating some more advanced customizations for ListViews, and other cool Android programming tricks.
Download the source: customizing-android-listview-example.zip

Get 50% off my Node.js course here

If you liked this article, help me out by sharing a 50% discount to my Node.js course here: Thanks!

You should follow me on Twitter here:

  • Dan

    How can I set up Eclipse to use that color scheme?

  • http://twitter.com/scottagarman Scott A Garman

    You should add a section on how to use the ViewHolder method described in the googleio talks to create more efficient lists. http://www.youtube.com/watch?v=wDBM6wVEO70&t=17m38s

  • Pingback: /r/android, I’m starting a series of android development tutorial posts – here’s the first » App Crow

  • Pingback: Codehenge » Blog Archive » Android Programming Tutorial – A Simple Twitter Feed Reader

  • Pingback: casinos en ligne france

  • Pingback: Codehenge » Blog Archive » Android Programming Tutorial – A Simple Twitter Feed Reader

  • John
    • Anonymous

      Interesting read. I actually hadn’t heard the argument that LinearLayout was less efficient or could lead to performance degradation before, so thanks for the tip! I’ll be sure to do some testing and see if I can quantify a performance difference.

  • Mark Thompson

    This is a very helpful post! Much appreciated.

    I did notice one thing though:

    LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    This line causes a compilation error for me unless I change it to:

    LayoutInflater vi = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    I don’t know if this is an error on my part, but I just wanted to put that out there.

    Thanks Again!!

    MT

    • http://www.facebook.com/people/Ahmad-Abo-Rjelah/577202935 Ahmad Abo Rjelah

      yea i faced the same problem ,,,, thanks for your post

    • Jamie Welch

      Same problem here, thanks for the tip!

    • Babubujji27

      had the same problem. but solved when I created the Adapter class in the Activity file itself, instead of a separate file. Dont know what does that mean, am new to OOPS, but problem solved

  • JLong

    Hi how can we add a onclick listener to this please?

    • buka

      After playing with it for plenty of hours, finally worked with in me this way:

      ListView lv = (ListView) findViewById(R.id.listView1);
      lv.setAdapter(new UserItemAdapter(this, android.R.layout.simple_list_item_1, users));

      lv.setOnItemClickListener(new AdapterView.OnItemClickListener(){

      @Override
      public void onItemClick(AdapterView parent, View itemClicked, int position,
      long id) {
      // TODO Auto-generated method stub

      if (position == 0 ){
      startActivity(new Intent(getApplicationContext(), R1.class));
      }else
      if (position == 1){
      startActivity(new Intent(getApplicationContext(), R2.class));
      }else
      if (position == 2){
      startActivity(new Intent(getApplicationContext(), R3.class));
      }

  • Singh Abhi4690

    How Can we add ListItemClickListener please???

  • http://www.oraculum.blog.br Oraculum

    thanks !!!

  • http://www.oraculum.blog.br Oraculum

    private OnItemClickListener clickList = new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView arg0, View v, int position,
    long arg3) {
    Endereco end = ((Endereco)list.getItemAtPosition(position));
    String id = end.id.toString();

    Intent i = new Intent(ListarFamiliaActivity.this,
    AddFamiliaActivity.class);
    startActivityForResult(i, 0);
    }
    };

  • Mystrious112

    Nice!!!!! it worked well

  • Franklin Peña

    You don’t need

    private ArrayList users;

    Since the adapter holds a an implicit collection of this type by way of extends declaration

    and the following lines must go away after taking out the users member above

    this.users = users;

    The following line

    UserRecord user = users.get(position);

    gets substituted by

    UserRecord user = this.getItem(position);

    Otherwise it all works!

    Thanks and keep the good work.

  • oskar

    Using android.R.layout.simple_list_item_1 is misleading since you’re making your own, customized list item. A better way would be to rename the listitem.xml to mycustomizedlistitem.xml and refer it as R.layout.mycustomizedlistitem.

  • Oskar

    oups, you already did that. my bad :)

  • ravich

    how to display icon in menu view i am try to this code but no display icon……

    private void CreateMenu(Menu menu)
    {
    menu.setQwertyMode(true);
    MenuItem mnu1 = menu.add(0, 0, 0, “Item 1″).setIcon(R.drawable.ssss);

    {
    mnu1.setAlphabeticShortcut(‘a’);
    mnu1.setIcon(R.drawable.ssss);
    }
    MenuItem mnu2 = menu.add(0, 1, 1, “Item 2″);
    {
    mnu2.setAlphabeticShortcut(‘b’);
    mnu2.setIcon(R.drawable.sample_1);
    }
    MenuItem mnu3 = menu.add(0, 2, 2, “Item 3″);
    {
    mnu3.setAlphabeticShortcut(‘c’);
    mnu3.setIcon(R.drawable.sample_2);
    }
    MenuItem mnu4 = menu.add(0, 3, 3, “Item 4″);
    {
    mnu4.setAlphabeticShortcut(‘d’);
    }

    }*/

  • Ivan1488

    Hi how can we add a onItemClick to this please?

  • Anudeep

    can we save the list item in ListView and retrieve the item and place in next acticity but how????
    ?

  • vixo

    no funciona tu codigo

  • Neo An

    So clearly code! Thanks for sharing, man :)

  • Gigel

    AWESOME.

    Might want to add a complete project too. Nevertheless, thank you!

  • -W

    Great example! Saved me a lot of time. Thanks.

    • http://www.codehenge.net Constantine Aaron Cois

      You’re welcome!

  • buka

    Thanks that example was the best among what I’ve went through, Thanks a lot.

    For adding click response to the items I came up with this way:

    ListView lv = (ListView) findViewById(R.id.listView1);
    lv.setAdapter(new UserItemAdapter(this, android.R.layout.simple_list_item_1, users));

    lv.setOnItemClickListener(new AdapterView.OnItemClickListener(){

    @Override
    public void onItemClick(AdapterView parent, View itemClicked, int position,
    long id) {
    // TODO Auto-generated method stub

    if (position == 0 ){
    startActivity(new Intent(getApplicationContext(), R1.class));
    }else
    if (position == 1){
    startActivity(new Intent(getApplicationContext(), R2.class));
    }else
    if (position == 2){
    startActivity(new Intent(getApplicationContext(), R3.class));
    }

  • Zonamsss

    Simple but precise; good one ma8:)

  • vidu

    good tutorial…………

  • Xotic Jerk

    How can i change the each object value by user input manually?any method or something else?

  • OhadGros

    how can i add a button to the listView and make an event when the button item is clicked

  • Digvijay Girase

    thanks man. it is just what i needed

  • oppa

    Very good and helpful for me!

  • Duy Ha

    great thanks for your excellent tutorial !

  • JonC

    I just want to thank you so much for posting this. Downloading your source code and implementing the list into my project was very easy and intuitive. I have searched hours for a simple solution to using subitems in a listview and yours works perfectly. Thank you!!!!!!

43 queries in 1.525 seconds