Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Custom listview course?

Would it be possible if someone could do a deep dive on Custom Listviews for Android?

I searched on the internet and did not find anything good..

I'm reaally confused with custom Listviews and Custom Adapters etc..

That reaally would be great ! :)

20 Answers

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

It's unfortunately a lot of code, but the basic idea is:

  1. Design your layout
  2. Create an adapter that adapts your data for the layout. The adapting happens in the getView() method, which gets called to set up each row in your list.
  3. Use your adapter in your activity

The following is untested code, but hopefully it's good enough to get you started. Feel free to post follow ups, though my availability in the forum is more limited on the weekends. :)

First you'll need a layout like this, named something like custom_row_layout.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:layout_margin="15dp"
        android:scaleType="fitCenter"
        android:background="@drawable/test_image" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/imageView1"
        android:layout_alignParentTop="true"
        android:text="test1" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/imageView1"
        android:layout_below="@id/textView1"
        android:text="test2" />

</RelativeLayout>

Then you'll need a custom adapter class, like this. Notice that custom_row_layout is used twice. This is based on having a CustomObject class that holds your text data for each item (and possibly the image filename):

public class CustomAdapter extends ArrayAdapter<CustomObject> {

    public static final String TAG = CustomAdapter.class.getSimpleName();

    protected Context mContext;
    protected LayoutInflater mInflater;
    protected ArrayList<CustomObject> mItems;

    public CustomAdapter(Context context, ArrayList<CustomObject> items) {
        super(context, R.layout.custom_row_layout, items);
        mContext = context;
        mItems = items;
        mInflater = LayoutInflater.from(mContext);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.custom_row_layout, null);

            holder = new ViewHolder();                
            holder.imageView = (ImageView) convertView.findViewById(R.id.imageView1);
            holder.textView1 = (TextView) convertView.findViewById(R.id.textView1);               
            holder.textView2 = (TextView) convertView.findViewById(R.id.textView2);               
            convertView.setTag(holder);
        }
        else {                
            holder = (ViewHolder) convertView.getTag();
        } 

        final CustomObject item = mUsers[position];

        holder.imageView1.seBackgroundImage(mContext.getDrawable(R.drawable.image_name);
        holder.textView1.setText(item.getText1());
        holder.textView2.setText(item.getText2());

        return convertView;
    }               

    private static class ViewHolder {                   
        ImageView imageView; 
        TextView textView1;  
        TextView textView2;  
    }
}

Then you use the adapter in an Activity, like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_select_users);

        // mItems will be an ArrayList<CustomObject>
    CustomAdapter adapter = new AdapterAdapter(MainActivity.this, mItems);
    setListAdapter(adapter);
}

There's a lot I'm glossing over for time's sake, but I will definitely cover this in video down the road!

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

Definitely on the list of topics to be covered! In the mean time, check out this tutorial from vogella.com: http://www.vogella.com/articles/AndroidListView/article.html

Specifically, follow the section called "Developing a custom adapter."

Thank you for this link!

I already knew that tutorial, but what gets me confused is the difference between a custom adapter and the listayout..

And the vogella tutorial is confusing for me because there are so many different things :/

But I'll try searching for tutorials :)

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

Sure - I think it takes writing a few custom adapters to put all the pieces together. For me it definitely helps to isolate the layout and the adapter. I design the layout how I want it and then work on the adapter to make sure I'm getting the right data elements in the right spots in the layout.

I don't have a lot of publicly-available code to share, but if an example would help, check out the UsersAdapter of this ReadMe app I wrote for a Treehouse presentation. The adapter is used in the SelectUsersActivity, but perhaps it will show you how I tie the custom layout to the custom UsersAdapter.

Feel free to drop questions in here and I'll try to answer in case it will help anyone else!

The app is awesome! When I know android programming a bit better, I want to do a similar app for my website with the same plugins and login :)

So your app helps me to learn a lot! Thank you !

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

Cool - very glad to hear it! I know I like to learn by example when I can. Also, I recorded a workshop for Treehouse on the Parse.com integration, and that should be available before too long.

I found a very good eboook for listviews and other elements of android developing :)

http://www.amazon.de/Android-Application-Development-Cookbook-Building/dp/1118177673

The book explains customadapters and so on very simple and easy to understand :)

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

I have this Android Recipes book from Apress. I haven't read much of it yet, but it looks good, and I like the author (from Twitter). :smile: I got the ebook for half off--they run promos like that now and then.

Just in case someone reads this

http://tekeye.biz/2012/two-line-lists-in-android

this is a very good tutorial explaining the listview and the hashmap

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

Thanks @Fabian! I'm going to add that post to the video notes. I wish two line lists were simpler in Android! Sometimes iOS has all the fun... :smile:

@Ben Sooorry if the notifications you get may annoy you :P

I'm now trying to write my first "useful" app..

It's reall simple at first a Array with strings gets initialized

private String[][] picturelist= {{ "example", "example" }, };

then I push this into a list with this

HashMap<String, String> item; for (int i = 0; i < bilderliste.length; i++) { item = new HashMap<String, String>(); item.put("category", bilderliste[i][0]); item.put("description", bilderliste[i][1]);

        list.add(item);
    }
    sa = new SimpleAdapter(this, list, R.layout.bilderliste, new String[] {
            "category", "description" }, new int[] { R.id.category,
            R.id.description });

that works out pretty good, but now I want to add a picture to the array.. and don't really know how to do that.. I searched a lot of tutorials, but they were not what I needed..

Maybe someone could help me a bit, I'm really stuck..

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

@Fabian, helping you and the other members is why I love my job! :smile:

Quick question: Where do you plan on getting the images from? Will they be in your res directory, or will you download them from the web? Downloading from the web is harder, but there's an open source library you can use from GitHub that makes it super easy. Let me know which you're after and I can walk you through it. But basically you need to create a custom layout file for each row that has an ImageView and two TextViews. Then you need to map everything manually like my UsersAdapter example from above.

@Ben And that's why we (I) love you ! :D

I'm planning to get them from my res folder, I already did a xml file with two lines and one image, I already tried some things from tutorials.

But I'm really confused now.. :/

Thank you a lot! :)

That really helps

But what is the "CustomObject"?

Maybe It's obvious and I'm just to confused right now :P

And a main question for me is: When to use which ArrayLists and when to use what kind of adapters.. ArrayLists are confusing for me, because we already have a Array, why should we something like a ArrayList?

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

Sorry, I shouldn't have assumed anything! CustomObject is meant to be a file named CustomObject.java that you make like this:

public class CustomObject {
    protected String mText1;
    protected String mText2;
    protected String mImageFilename;

    public CustomObject(String s1, String s2, String imageFilename) {
        mText1 = s1;
        mText2 = s2;
        mImageFilename = imageFilename;
    }

    public String getText1() {
        return mText1;
    }

    public void setText1(String text) {
        mText1 = text;
    }

    // ... other getters and setters omitted ...
}

You would create an ArrayList of these based on your data rather than using an array of Strings (or a two-dimensional array of Strings like your `picturelist`).

Oftentimes you can choose a regular array or ArrayList. I think my example would work with a regular array of CustomObjects... ArrayList gives you a little more functionality than a regular array, and some adapters require an ArrayList instead. Let me know if changing to a regular array works!

I now found a (kind of) library for doing lists really easy

https://github.com/thest1/LazyList

and

https://github.com/nostra13/Android-Universal-Image-Loader

which is based on the above, but further maintained :)

I think i'll use this, because i don't like to reeinvent the wheel :D

I probably can't answer, because after i bought my SGS4, I'm to poor for treehouse ^^

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

Awesome - good finds! :) Thanks for sharing the links, too! Here's a good site for discovering new libraries: Android Views

I have a major problem with my listview..

I managed to do a customadapter using LazyAdapter and a class for my object..

the listview shows up only when I install the app on my device, after that the listview gets blank..

Ben Jakuben
STAFF
Ben Jakuben
Treehouse Teacher

We don't officially support custom projects from members, but if you want to zip up your project and email it to help@teamtreehouse.com then I can take a look and see if anything jumps out. Make sure you indicate that it's Android and for me in your subject (like "Android project files for Ben").