Featured Post

Excluding URLs from the security-constraint in App Engine

I was playing and searching around for how to exclude a URL from the security constraint in the web.xml file in App Engine. For my application everyone has to be authenticated to access anything in the application and I don’t want to add every URL to the pattern. So my first security constraint...

Read More

ListView with Sections/Separators

Posted by Bartinger | Posted in All, Tutorials | Posted on 11-07-2011

Tags: , , , , , ,

32

Sectioning ListViews

Edit: ListView tutorial part 2 is about clickable widgets in ListView items Take a look!

If you’ve ever used ListView, and i bet you had, then you will have noticed that it is not very handy if you want to display a huge amount of data. I found a few solutions, how to categorize list items like in your phones preferences. This post won’t be about how it looks rather more about how to write it. I’ll show you 2 solutions and describe one if it more detailed. There is no perfect solution, but you can decide which one you prefer.

Solution #1:

Sectioning in ListViewsOne is to include the Sectionview in every item of your list and set its visibility to “GONE”. Then make it visible in each first item. I don’t like this one, because then you have a lot of  unused TextViews (or whatever) which consume memory. Not so much to worry about, but i think solution #2 is easier to understand and expand. If you want to read much more about ListView and sectioning it, Cyril wrote a great post about it. And here is my preferred way to sectioning list items.

Solution #2:

I didn’t like the first version so i thought about my own way to do it. (Before Cyril’s post was written :) ). So what did  I do?

I created 2 xml files. One for the section and one for the list item. If you want to have your section item look like that one in the preferences you can get its attributes like that:

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

	<include
		android:id="@+id/list_item_section_text"
		layout="@android:layout/preference_category" />

<LinearLayout>

Of course you can design your section how you want.

The second xml is for all the list items. I copied it from another project of mine and you can use it if you want to.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:gravity="center_vertical"
    android:paddingRight="?android:attr/scrollbarSize">

    <ImageView
        android:id="@+id/list_item_entry_drawable"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:src="@android:drawable/ic_menu_preferences"
        android:paddingLeft="9dp"/>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dip"
        android:layout_marginRight="6dip"
        android:layout_marginTop="6dip"
        android:layout_marginBottom="6dip"
        android:layout_weight="1">

        <TextView android:id="@+id/list_item_entry_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:ellipsize="marquee"
            android:fadingEdge="horizontal" />

        <TextView android:id="@+id/list_item_entry_summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/list_item_entry_title"
            android:layout_alignLeft="@id/list_item_entry_title"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:singleLine="true"
            android:textColor="?android:attr/textColorSecondary" />

    </RelativeLayout>

</LinearLayout>

You can see how these  layouts look like on the screenshot above. Next step is the java code.

I created 3 classes and one interface.

  • EntryAdapter (ArrayAdapter)
  • Interface: Item
  • SectionItem (implements Item)
  • EntryItem (implements Item)
The Item interface contains the method: isSection(); This will return true when it’s a SectionItem and return false when it’s a EntryItem so that we can keep the two apart. Item, EntryItem and SectionItem aren’t that hard to understand, because there isn’t really much code. There are included in the project zip file at the end of the post. The Adapter should be a explained in more detail. Here’s the code:

public class EntryAdapter extends ArrayAdapter {

	private Context context;
	private ArrayList items;
	private LayoutInflater vi;

	public EntryAdapter(Context context,ArrayList items) {
		super(context,0, items);
		this.context = context;
		this.items = items;
		vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View v = convertView;

		final Item i = items.get(position);
		if (i != null) {
			if(i.isSection()){
				SectionItem si = (SectionItem)i;
				v = vi.inflate(R.layout.list_item_section, null);

				v.setOnClickListener(null);
				v.setOnLongClickListener(null);
				v.setLongClickable(false);

				final TextView sectionView = (TextView) v.findViewById(R.id.list_item_section_text);
				sectionView.setText(si.getTitle());
			}else{
				EntryItem ei = (EntryItem)i;
				v = vi.inflate(R.layout.list_item_entry, null);
				final TextView title = (TextView)v.findViewById(R.id.list_item_entry_title);
				final TextView subtitle = (TextView)v.findViewById(R.id.list_item_entry_summary);

				if (title != null)
					title.setText(ei.title);
				if(subtitle != null)
					subtitle.setText(ei.subtitle);
			}
		}
		return v;
	}

The interesting part is the getView() method. Here you have to keep the two apart and inflate either the section xml or the entry xml. Cast the item, then inflate the right xml to get the view. Setup the TextViews or whatever you use in your items and then return the view.

Now how to actually add items in your activity (I use ListActivity for this example):


ArrayList items = new ArrayList();

items.add(new SectionItem("Category 1"));
items.add(new EntryItem("Item 1", "This is item 1.1"));
items.add(new EntryItem("Item 2", "This is item 1.2"));
items.add(new EntryItem("Item 3", "This is item 1.3"));

items.add(new SectionItem("Category 2"));
items.add(new EntryItem("Item 4", "This is item 2.1"));
items.add(new EntryItem("Item 5", "This is item 2.2"));
items.add(new EntryItem("Item 6", "This is item 2.3"));
items.add(new EntryItem("Item 7", "This is item 2.4"));
EntryAdapter adapter = new EntryAdapter(this, items);

setListAdapter(adapter);

Pretty simple huh? :) There’s just one thing that you have to take care of. In the onListItemClick() method (and long click as well of course) you have to check if the clicked item isn’t a Section item.


if(!items.get(position).isSection()){
    		EntryItem item = (EntryItem)items.get(position);
    		Toast.makeText(this, "You clicked " + item.title , Toast.LENGTH_SHORT).show();
}

Thats all. It’s definitely not the best solution, but I thinks its kinda handy and easy to understand. I tested it with 2000 items and had no problem running it on the emulator and on my device. The full example can be downloaded here. SectionListExample (1584)

If you have any questions feel free to leave a comment and I’ll reply as soon as possible. So have a nice day.

Subscribe to this blog Add to Google
  • Mamil

    exactly what im looking for thaks

  • kdawg

    Great post.   Will this implementation support fast scrolling? In particular, what would be great is to  have fast scrolling where only the “section items” appear in the zoomed view.  I am a bit new to this and would appreciate your thoughts.

    • Anonymous

      Just call:
      getListView().setFastScrollEnabled(true);
      and you will have the drag-able Image on the right.
      I’ll have a look on it with the SectionItems.
      Maybe I’ll make an Part 2 of this Tutorial with fastscrolling

  • masterodst

    How do you use the items to start a new activity instead of using the toast?

    • Anonymous

      Of course. just start the activity as usual with startActivity(new Intent(…)); instead of the Toast.makeText(…) line.

      • masterodst

        Hmmm.  I have wrote the startActivity(new Intent(…)); a few times but have gotten errors on the specific title i’m clicking on.  Toasting works perfect but startActivity crashes.  Any tips for that?  Thanks for the help

      • masterodst

        Another day, more headaches… I created the startActivity but i’m stuck… here is my code…
            protected void onListItemClick(ListView l, View v, int position, long id) {        if(!items.get(position).isSection()){        EntryItem item = (EntryItem)items.get(position);        startActivity(new Intent(null, Item12.class));

        Fails everytime.

  • Brandon Ulasiewicz

    This is a great resource.  Thanks for the post :-)

    I have a quick question about this … is there a way to have a static background image to be placed behind everything so that when you you scroll the image will stay put and the list will scroll?  

    • Anonymous

      Sorry I forgot to answer to your comment. What you can try is to create a layout via xml with a LinearLayout and a ListView in it. Set the background image to the LinearLayout and make the background of the list items transparent.

  • dhara

    Thanks  for the post

  • Dhara

    Please tell me If any one have idea for Pagination in android. Is it posssible?

  • Raven3221

    What about View Holder pattern?
    You’re not reusing the views that were already created.
    Solution 1 can use this pattern and save a lot of inflating.

    • Anonymous

      I know. I already created a list with a holder. I’ll put up another tutorial with this pattern soon.

  • Amjath

    good post.  really useful for me to implement categorized list view

  • http://twitter.com/thomagr Thomas Gravina

    Hi,

    And thanks for this great tutorial. It really helped me. I think lot of people appreciate to have an example to download source :)

    I just have a question about Section. How can I make it “unfocusable”? I mean, to avoid it to be focusable when the user use trackball up/down?

    Thanks to all.
    Thomas.

    • Anonymous

      Hey Thomas, thanks for your comment.
      Regarding to your unfocusable question you can play around with these attributes. android:clickable=”false”
               android:linksClickable=”false”
               android:focusable=”false”
               android:focusableInTouchMode=”false”I didn’t test them but I would try to add them to the include tag in the section item xml file. Please let me know if it worked so that i can add them to the tutorial.Best

  • Klymentiy Haykov

    How do you do this while recycling views?

  • http://twitter.com/Quarkmus Markus Weller

    Is there anything I have have to take care of if this is not my main Activity?
    I have writen a XML File with a list in it and have a setContentView to this View.But nothing is displayed, my list remains empty and the getView Methode is never used.

    • Anonymous

      Hey Markus.

      If you’re using a normal Activity instead of a ListActivity like me and added the ListView via the XML layout, you have to change this line: “setListAdapter(…)” to something like this…

      ListView listView = (ListView) findViewById(R.id.your_listview);
      listView.setAdapter(adapter);

      Did you do that ?

      • http://twitter.com/Quarkmus Markus Weller

        No i’m using a ListActivity, but without “setContentView(R.layout.view);” the screen remains black.
        Nearly everything in my Programm is equal to the demoApp, exept that i have to retrieve the data in the “onCreate” First, and that im changing the Picture in the getView(), but this method is never used.

        • Anonymous

          You should create a question on http://stackoverflow.com/ with some code and post it here then …

          • http://twitter.com/Quarkmus Markus Weller

            I solved it, I use a AsyncTask, and this wasnt ready when I filled the list, so she always was empty. I had to fill the adapter and set the adapter after finishing the AsyncTask.

  • DroidRookie

    That helps Bartinger.

    A simple and effective piece of code which never flashed in my brain

  • http://www.facebook.com/profile.php?id=1628649395 Damiano Corrado

    Thank you

  • _xenix

    Hello, good post. I want explication under the question “I have a quick question about this … is there a way to have a static
    background image to be placed behind everything so that when you you
    scroll the image will stay put and the list will scroll?” i not understand how do you do… Thanks

  • Mahesh Chunkhade

    hello..it is really very good tutorial for section list view..

    it help me lot to understand how to construct section list view 

    thanks

  • Amit Mohite27

    nice post, very helpful

  • Yusuf Wagh

    Great Example Helped me a lot but i had an Issue i have used your structure my listview row contains images which are coming from server and when i scroll it again n again it gets crashed and memory warning is issued .. because layout is getting inflated every time 

  • Padman009

    Hello there,the code is excellent but how can I use different icons for the list items?

AndroidPIT