Featured Post

Organization tips for Android projects

If you develop apps for Android you may have noticed, that you quickly lose the overview of your layouts, ids, drawables, packages, etc. I want to share my experience with you and suggest a few tips, how to organize your projects. I consider myself to these rules, because they help me (and...

Read More

ListView with Sections/Separators

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

Tags: , , , , , ,

60

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 (5548)

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 

    • apache

      Yes :) After one year I discovered it. How did you menaged it?

      For me putting

      if (v==null){

      }

      in getview
      kinda solved problem

  • Padman009

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

  • Usha Keesara

    in this program where is the main.xml calling

  • Johnnie Hammonds

    First off, I want to say thanks for the post.  You’ve done a really nice job with it.  I also thought I would mention that I extended your work a bit to make the Activity generic. This allows me to use the same set of classes for any number of custom lists that I want.

    To do this, all I had to do was pass in the ArrayList via the intent when starting the activity (using startActivityForResult), then return the selected item as a result when exiting the activity.

    Thanks again!

    • Bartinger

      glad i could help!

  • tote

    @Bartinger:disqus : Helpful post, for sure. I’m having problems applying it when I have many items in my list where the user has to scroll through the items.It seems that only the items in view are retrieved through get view. So at first my list and headers look fine. Once I start scrolling down past what was initially visible, for some reason I get repeats of headers that should not be there. My items arrayList looks fine structurally. I have a section i position 1. 1 item under that section. Then another section. Then 27 more items for that section. But when I start scrolling things get messed, and I get duplicate sections with items that belong to another section etc…. anyone see anything like this?

  • tote

    ok i was able to correct my code by removing i check in the getView event. The code I had was checking to see if convertView had already been inflated and set to something and if it had to just return it as is. I removed the check and now just have it inflate a new view for each row all the time and I get the data I want, but the scrolling seems to lag a little bit.

    • Bartinger

      Yes, sorry that I couldn’t reply. I had the some problem once and did the same mistake.

  • Allene

    Great Post. It Helped me a Lot in creating section list view.

    I have a created a listview with your code, with a little modification to the xml file. i removed one textview and inserted edittext view in the xml file. now i want to get the value from the edittext view form each item and store it in respective variables for further calculation. problem is i can’t get the value through findViewById, because i have only one ID for edittext view. i have no idea how to solve this problem. 

    • Bartinger

      I wouldn’t even put a EditText into a ListView. What I would do is to pop up a dialog with an EditText and then let the user make his input there. However if you really want to have it in your ListView you could store the EditText in the EntryItem and when you click on it you read the value 

  • udi

    thank you very much

  • Ivan

    This is a very useful tutorial. I need a longest Listview so i´ll add more items and done. I have a question, I would also like to have an image on each section (but different in each one) as
    there is
    only a list_item_section, how can I do it? Thanks in advance and congrats again for the tutorial

    • Bartinger

      So what you want is a different image in each section-item?

      • Ivan

        Yes, would it be possible?

        • Ivan

          and if so, how can I do it??

        • Bartinger

          If you want a background image just add an id to the LinearLayout in the section xml-file and set the background image in your code.

          Or you just add an ImageView and set the image in code, but I’m not quite sure if that works.
          You have to edit the section xml-file though.

          • ivan

            I´m really lost Bartinger, i´m sorry. I have to modify list_item_section.xml I thought it was easier by adding an ImageView but I don´t know how to set the image because it would be different in every section and if I add a background image in LinearLayout I don´t know how to add the different image in each section. Thanks again my friend

            • Bartinger

              In the SectionItem class add a new field

              private final int drawableID;
              You need to update the constructor and add getters as well. In the getView method if the item is a SectionItem you just get your ImageView exactly like the TextView and with
              imageView.setImageResource(si.getDrawableId());
              you can set the Image

              • Ivan

                I dis as you said, this is SectionItem:
                private final String title; private final int drawableID; public SectionItem(String title, int drawableID) { this.title = title; this.drawableID = drawableID; } public String getTitle(){ return title; } public boolean isSection() { return true; }
                public int getDrawableID() { return drawableID; }

                with private final int drawableID; and public int getDrawableID().
                Then I add in EntryAdapter
                final ImageView imageView = (ImageView) v.findViewById(R.id.list_item_entry_drawable);imageView.setImageResource(si.getDrawableID());
                And now to add the image in the main activityitems.add(new SectionItem(“Euromillones”, R.drawable.circulo_blanco)); and the app doesn´t. Do I need to add an ImageView in list_item_section.xml before the include?

                Thanks again to be so patient

  • Steph

    Hi!

    First, congrats for that sectionned listview, very nice! :-D

    I am just wondering how could it be possible to include a footer within?
    Could you maybe help? ;-)

    Thanks.

  • Steph

    Hi!

    First, congrats for that sectionned listview, very nice! :-D

    I am just wondering how could it be possible to include a footer within?
    Could you maybe help? ;-)

    Thanks.

  • Steph68

    Hi!

    First, congrats for that sectionned listview, very nice! :-D

    I am just wondering how could it be possible to include a footer within?
    Could you maybe help? ;-)

    Thanks.

    • Steph68

      Sorry for multiple posts.

      I expected to see my question sorted by date, on the top of the list, so I meant it didn’t worked…

  • Pingback: Using ListActivity inside PagerAdapter | Jisku.com

  • Oli Viner

    Great tutorial. I have been parsing a JSON with items and sub-items and this has worked a treat, except for one major issue – the SectionItems are appearing in a random order?! The entries are associated with the correct sections but the sections are all over the place. When I check the JSON or parse it using an expandable listview (which I do not want as it is very slow and I want the groups permanently expanded) they are in the correct order. Any ideas why this may be happening?

  • hongken

    I really appreciate it. You saved me !!!

  • Bhupendra

    how to categorized the expandable listview like same u did for listview

  • Miguel Angel Jimenez Sanchez

    good job, you could join your proyect to http://www.theultimateandroidlibrary.com/

  • James

    awesome..but how to remove a row using this approach?

AndroidPIT