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):
(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:
- The outermost element is a RelativeLayout. This is essential, so you can position the inner elements relative to each other.
- The footer has the
android:layout_alignParentBottom="true"
attribute. This is required to make it stick to the bottom. - 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.
- 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.
May 27th, 2010 - 01:49
Wow, great article! I was looking for something nice and clear and your solution is great. Thanks!
June 15th, 2010 - 09:07
This works on my Motorola Backflip Android v1.5! Thanks!
June 15th, 2010 - 09:57
No prob, glad it worked for you! (and for Android 1.5)
July 1st, 2010 - 09:13
Thanks for this, after a bit of trawling I came across your answer and it works great.
July 1st, 2010 - 09:30
Glad it worked for you.
July 10th, 2010 - 14:01
thanks. this worked !
July 10th, 2010 - 22:11
Awesome, Mag
July 20th, 2010 - 16:50
Thanks!!! really useful…i’ve been looking for something similar a long time!!
July 20th, 2010 - 17:36
Glad to hear it, lurecas. Took me a while to figure out, too.
August 3rd, 2010 - 10:02
thank you!
October 17th, 2010 - 09:02
What would the java look like for this script?
October 18th, 2010 - 14:18
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!
October 19th, 2010 - 10:25
great job, i spend few hours tring make this.
October 19th, 2010 - 11:51
Glad it helped.
October 22nd, 2010 - 08:31
“Surprisingly, the header and footer both have to show up above the listview in the xml tree.”
This was invaluable … thanks
November 5th, 2010 - 17:14
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.
November 6th, 2010 - 20:07
Don’t have any experience with your problem, unfortunately, but perhaps these resources will help:
Sorting Android ListView
How can I sort items in the ListView?
Best of luck.
November 9th, 2010 - 05:47
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
November 9th, 2010 - 08:59
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
November 11th, 2010 - 07:33
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 !
November 11th, 2010 - 08:23
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.
November 11th, 2010 - 10:06
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.
November 11th, 2010 - 11:03
You know, I actually tried those, and I just couldn’t get them to work. But maybe I was doing it wrong.
December 8th, 2010 - 20:19
You only spend hours figuring it out? I have spend days getting a footer textview which dosent get overrun by listview.
Great thanks.
December 9th, 2010 - 09:08
Ha, well…probably for the better. If it had taken days I would have given up
December 10th, 2010 - 07:51
Thanx, works great.
January 7th, 2011 - 06:56
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 !
January 10th, 2011 - 08:22
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
January 14th, 2011 - 00:24
Works great. Many thanks. I used it for search, where I replaced the spinner with an EditText and results goes to the ListView.
January 14th, 2011 - 12:53
Awesome, sounds spiffy.
February 13th, 2011 - 22:24
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.
March 9th, 2011 - 07:41
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.
March 9th, 2011 - 18:14
Great! I’m glad this advice is still relevant Might have to re-evaluate it in light of the Honeycomb/Fragments API stuff, though.
April 8th, 2011 - 04:54
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?
April 8th, 2011 - 07:11
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.
April 17th, 2011 - 08:14
Nice post!
Thx bro.. Keep posting!
April 21st, 2011 - 12:38
// 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
April 21st, 2011 - 12:40
hmm.. guess some of the code got stripped. Here’s the pastebin
http://pastebin.com/JZqnKLDB
April 22nd, 2011 - 09:10
Thanks a lot for posting this! Others have been looking for this, I know. I’ll point it out in the post.
April 23rd, 2011 - 11:58
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???????
May 18th, 2011 - 09:20
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.
November 24th, 2011 - 17:50
I agree.
July 8th, 2011 - 09:04
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!
July 9th, 2011 - 08:57
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.
July 12th, 2011 - 05:25
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
July 13th, 2011 - 21:04
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.
July 19th, 2011 - 23:08
hi
I want not that header should not move when I call for inbulid phone dialer.
So can you help me.
August 9th, 2011 - 12:33
Thank you very much, tried using addHeaderView() without success, your method works great.
September 27th, 2011 - 12:08
Thanks, very good example!
October 8th, 2011 - 23:15
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.
November 23rd, 2011 - 00:38
my list is not showing up after doing this ..i want a fixed footer which is always on top
November 23rd, 2011 - 17:35
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.
November 24th, 2011 - 18:21
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 …
December 1st, 2011 - 01:53
Can this be the alternative solution to action bar?
December 1st, 2011 - 13:53
Very, very, very useful.
Thanks,
Mario
December 14th, 2011 - 05:56
It was really helpful for me too. Thanks.
December 26th, 2011 - 01:21
Thanks
December 29th, 2011 - 03:14
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.
March 2nd, 2012 - 10:18
Thanks. I cannot believe how tricky it has been to achieve this in Android. iOS is no problem.
March 2nd, 2012 - 10:18
Well…it’s certainly not a pattern that Android hands to us on a platter unfortunately.
March 19th, 2012 - 19:48
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.
April 24th, 2012 - 00:40
Thank u very much..
it works for me…
May 25th, 2012 - 00:30
You are awsome Max !!!
You saved my life.
Good karma for You
May 30th, 2012 - 05:21
Thanks dude! Jeesus how this can be so difficult…
July 4th, 2012 - 00:14
thanks a lot!
September 10th, 2012 - 10:06
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!
September 20th, 2012 - 15:24
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.
September 22nd, 2012 - 18:59
Many thanks – cheers
November 28th, 2012 - 04:13
Nice work !
December 19th, 2012 - 22:48
Thanks a lot…
April 24th, 2013 - 23:06
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 !!
July 26th, 2013 - 13:13
Well explained and thank you. Saved me about 5 hours of googling around without getting a complete answer and explanation.