occasionally useful ruby, ubuntu, etc

11May/1072

Attaching a sticky (fixed) header/footer to an Android ListView

In my Android app, I have a ListView, and I want to persist a button at the bottom of the page (like how the Gmail app has Archive, Delete, and Older on the View Email screen). Unfortunately, this is not trivial, and many others have tried, but despite those suggestions, I never found something that quite worked correctly. The third article above got me actually pretty close, so without further ado, here's a working solution (images and javascript include after the jump):

ListView with Footer, Non-Scrolling

ListView with Footer, Scrolling

(you'll probably want to view that XML at gist by hitting the gistfile1.xml or view raw links)

This creates a view with a header bar (for sorting), a list view, and a footer bar (for common tasks). When the list view has enough items to warrant scrolling, the list rows do NOT bleed "through" the footer, and when the list is short the footer does not rise up.

Initial setup: there's the root element, a relative layout. There's a relative layout inside that with id top_control_bar, which is the header. Then there's a linear layout with the footer, id bottom_control_bar. Finally there's the list view for when there's content, and the text view for when there's no content.

So some things to notice:

  1. The outermost element is a RelativeLayout. This is essential, so you can position the inner elements relative to each other.
  2. The footer has the android:layout_alignParentBottom="true" attribute. This is required to make it stick to the bottom.
  3. Suprisingly, the header and footer both have to show up above the listview in the xml tree. This is so that the listview can reference the ids of the header and footer for positioning. I presume this is because the XML parser resolves IDs in a single pass.
  4. The ListView has android:layout_below="@id/top_control_bar" android:layout_above="@id/bottom_control_bar" so that it will always be below the top bar and above the bottom bar.

Definitely spent a couple hours figuring this one out, so I hope this helps!

p.s. I only tested this out with the Android 2.1 emulator...hopefully it works for others as well.

EDIT 4/22/2011: One of the commenters kindly provided the Java equivalent of this, click here to jump to it.

Filed under: android Leave a comment
Comments (72) Trackbacks (4)
  1. Wow, great article! I was looking for something nice and clear and your solution is great. Thanks!

  2. This works on my Motorola Backflip Android v1.5! Thanks!

  3. Thanks for this, after a bit of trawling I came across your answer and it works great.

  4. thanks. this worked !

  5. Thanks!!! really useful…i’ve been looking for something similar a long time!!

  6. What would the java look like for this script?

    • Hmm…I don’t know :( I’m not familiar really with using Java for layouts, but I imagine it would follow the same format. Create the header object, then the footer object, and then create the middle object and place it between them.

      Sorry I can’t be of more help!

  7. great job, i spend few hours tring make this.

  8. “Surprisingly, the header and footer both have to show up above the listview in the xml tree.”

    This was invaluable … thanks

  9. Well done!

    What would be the best way to sort the ListView alphabetically, without loosing the correct checked assignment.

    If you do it with Collections.sort(List,…) you sort the ListItems but the checked assignment remains at its orign position.

    Regards.
    snoop.

  10. Max, this is awesome.
    I had been googling for days, tumbled many ‘close’ solutions, but none has the clarity as your explanation.
    How I hope official Android development website includes more ready-to-use short examples like this, in addition of the complete and rigorous programming syntax

    Great work, Max

    • 6 months later, and this is still my most popular post. Glad to hear it helped you Lawrence, and many others I presume aren’t commenting ;)

  11. Great job – I spent most of yesterday climbing the “Learning Curve” on Android Layouts; and was getting a bit frustrated trying to do View positioning outside the realm of basic LinearLayouts. Glad I called it a day, since this morning I found your blog. Thank you Sir !

    • Yeah, it’s a bit tricky for sure. Not sure if I love it or hate it — I like the idea of positioning things relative to each other in a configuration file, and yet, I hate XML and various parts of the execution of the way Android does it.

  12. Thanks for the invaluable tutorial!

    But there is a addHeader(View v); method in ListView where you can attach a header and addFooter(View v); where you can attach a footer. If you are using only Java, that is.

  13. You only spend hours figuring it out? I have spend days getting a footer textview which dosent get overrun by listview.

    Great thanks.

  14. Hi,

    Is there anyone who try this new API 9 method : myListView.setOverscrollHeader(myDrawable);
    It’s seem do what we want to do …

    Thanks Max, a great tuto !

    • That does look relevant, but being an API 9 method it’s only Android 2.3, of course. Still not sure why addHeaderView and addFooterView don’t do what one might expect. However, do note this is what overscrolling is: “the ability to overshoot the bounds of a scrolling operation”. So normally there’s simply blackness above the top of a list, if you “force” a list off the screen — I think the overscroll header/footer simply allows you to replace this with something else.

      Source: http://developer.android.com/reference/android/widget/OverScroller.html

  15. Works great. Many thanks. I used it for search, where I replaced the spinner with an EditText and results goes to the ListView.

  16. How to extract this header and footer as a reusable part(xml)?And i was do some testing and got a problem with this xml?My env is android 2.2.

  17. Hi Max. Just tried you solution: it works really great!
    Many many thanks! :)
    I suggested it, too, as this StackOverflow answer: http://goo.gl/QodJJ.

    • Great! I’m glad this advice is still relevant :) Might have to re-evaluate it in light of the Honeycomb/Fragments API stuff, though.

  18. Where’s the Java?
    It’s worth nothing, without it, don’t you?
    No, I’m not saying that your code isn’t valuable…
    just: where is it?

    • Sorry, as I noted in another comment, there IS no Java, at least none that I’ve written. Shouldn’t be that hard for you to translate the XML I have into its Java equivalent, though. You could post a gist on github and link to it here and I’ll include it in the post, if you want.

  19. Nice post!
    Thx bro.. Keep posting!

  20. // thanks for working this out. I figured out the java code to implement thought I’d post it

    // myList.java
    package com.test.listview;
    import android.app.ListActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;

    public class myList extends ListActivity
    {
    /** Called when the activity is first created. */
    public void onCreate(Bundle icicle)
    {
    super.onCreate(icicle);
    // Create an array of Strings, that will be put to our ListActivity

    String[] names = new String[] { “Linux”, “Windows7″, “Eclipse”, “Suse”,
    “Ubuntu”, “Solaris”, “Android”, “iPhone”, “Linux”, “Windows7″,
    “Eclipse”, “Suse”, “Ubuntu”, “Solaris”, “Android”, “iPhone” };
    setContentView (R.layout.main);
    ListView listView = getListView();
    ArrayAdapter a = new ArrayAdapter (this, android.R.layout.simple_list_item_single_choice, names);
    setListAdapter(a);

    }
    }

    // strings.xml

    Hello World, myList!
    listview

    foo
    asdf
    qwer
    346346
    hjkg
    asdfasdfasd
    vbncvnb
    zxc
    hjkk
    tutrurty

    foo

  21. Thanks dude. Shockingly difficult to work with Android layout. HTML, CSS, WPF XAML, iOS Interface Builder (which is terrible), all of them were easier to reconcile than this. How can it be this hard to stack three elements vertically on top of one another???????

  22. I came across this post today and just thought I would point something out about your third point.

    ‘Suprisingly, the header and footer both have to show up above the listview in the xml tree. This is so that the listview can reference the ids of the header and footer for positioning. I presume this is because the XML parser resolves IDs in a single pass.’

    It is possible to position your elements in the XML file in any order you wish (for code-reading aesthetics mostly), by defining the ID of your bottom LinearLayout before you define the LinearLayout element itself.

    In your ListView’s layout_above attribute, you can define the ID with android:layout_above=”@+id/bottom_control_bar” (note the + sign). Then when you define your ID attribute for your bottom LinearLayout, you can just use android:id=”@id/bottom_control_bar” since the bottom_control_bar ID will have already been defined by your ListView above.

    Not sure if you already knew this by now, but I thought it might help someone else :)

    Cheers.

  23. Hi man,
    thanks for the article, it definitely pointed me to the right direction. I say “right direction” because you’re using too many layouts on inside the other with no need. Also that’s something that all the guys at google tell the developers not to do.

    you can achieve the same result using simpler stuff such as: http://pastebin.com/avfxJGY3

    which is using and Button at top, list in the middle and adview at bottom.

    thanks again!

    • Hmm, you might be right — I’m not sure the layouts wrapping a single element in the top bar or bottom bar is really necessary! But you also dropped the TextView that renders when the list is empty.

      IIRC, the Google docs say not to nest layouts excessively. I took that to mean like, 5+ nestings. Nesting a single layout inside of another shouldn’t give the layout engine any problems at all.

  24. I am not able to implement it on my file. I am new to android.. can you provide me java file code to implement this xml file

    • Hi Parikshit — I’m not really sure what you mean by java code to implement the xml. Have you looked at Declaring Layout? Or if you’re looking for a Java implementation to replace the XML, someone else implemented this and linked to it in the comments, which I linked again to at the end of my post.

  25. hi
    I want not that header should not move when I call for inbulid phone dialer.
    So can you help me.

  26. Thank you very much, tried using addHeaderView() without success, your method works great.

  27. Thanks, very good example!

  28. hey man , just came across this issue today – did a google search – yours was the first answer – clear consice with no extra baggage included to obscure the issue – if only some of the others had your ability to explain an issue while resisting the temptation to show off by focussing , laser like , on the issue in question. Thanks again … A sweet explanation.

  29. my list is not showing up after doing this ..i want a fixed footer which is always on top

    • Hmm, I can’t guess at what the problem is from that. If you paste the XML you have into a pastebin and link to it here, I can take a look at it.

  30. Hi Max, thanks for your help, it is really useful.

    However, do you know why the top layout has to be a relativeLayout ?

    I try to make it a linearlayout since I have several views in my top layout, but it just worked when I wrapped them all in a relativelayout …

  31. Can this be the alternative solution to action bar?

  32. Very, very, very useful.
    Thanks,
    Mario

  33. It was really helpful for me too. Thanks.

  34. thanks for your excellent presentation.i used for your code to my tab layout.my layout place at bottom.when i use your code as you there is given a problem like force close.
    i am waiting for your reply.
    thanks for advance.

  35. Thanks. I cannot believe how tricky it has been to achieve this in Android. iOS is no problem.

  36. hi, very good one but how to link this to java code though? how to add public header or footer()?
    I need some helps since I am very beginner with coding.

  37. Thank u very much..
    it works for me…

  38. You are awsome Max !!! :D
    You saved my life.
    Good karma for You :)

  39. Thanks dude! Jeesus how this can be so difficult…

  40. thanks a lot!

  41. I spent a lot time solving this issue.

    You’re solution is from far the best, easy and cleaner all arround internet

    thanks a lot!

  42. You sir are a genius and a scholar. I adopted your solution to my Relative Layout, and it works masterfully. Thank you so much for sharing this valuable information.

  43. Thanks a lot…

  44. it a simpler way to add a header instead of inflating a header view and adding it to a list view in code .Thanks worked well for me :) !!

  45. Well explained and thank you. Saved me about 5 hours of googling around without getting a complete answer and explanation.


Leave a comment