148

This is a pretty fine question about the layout of items in a ListView in Android.

I have an activity with a title bar at the top and a ListView taking up the rest of the screen. I want my ListView to appear with 10dp padding on the left, right and top, but when you scroll the ListView up, I want it to cover the top 10dp padding before disappearing under the faded edge. Similarly, when you scroll to the bottom, the last list item should appear with 10dp between the bottom of the last list item and the actual bottom of the screen (if you're wondering why, it's because there's a pretty background image that I want poking out around the ListView).

I've tried adding padding to the ListView itself, but then when you scroll the list it disappears under the edge of the padding.

I'm from a web dev background, and the analogy would be to add margin above the first list item (and below the last list item).

Mick Byrne
  • 14,394
  • 16
  • 76
  • 91
  • specify just the left & right margin... try to paste your xml here, so I can see the problem edit : wait, you mean.... You want the top and bottom padding got scrolled too? – Tek Yin Jun 09 '11 at 05:00
  • I can't specify the left and right margin - there is no 'margin' in Android layout, only padding. But, yes, I do want the top and bottom padding to get scrolled - that's a good way to describe it. – Mick Byrne Jun 09 '11 at 05:43
  • I already tried several method, and still failed.. I have some tricks to do, but it will more difficult to do though... you put 2 custom object to the list item on first and last position.. and use custom adapter to detect the item and draw it differently (narrow height & transparent) – Tek Yin Jun 09 '11 at 06:15
  • Yeah... that's what I've been thinking to fall back on as well. But there's all sorts of complications with that, as I'll then need to set the background color in the list items, not the view, which means I'll then need to manually hack in some effect to show when you've tapped things. Thanks for your help anyway... – Mick Byrne Jun 09 '11 at 06:28
  • Good news.. I got the solution... you can use addHeaderView(View v) on ListActivity.. just call `getListView(). addHeaderView(capView)` and `getListView(). addHeaderView(botView)` make sure it called before initialize the content of the list eg. setListAdapter(adapter); – Tek Yin Jun 26 '11 at 03:17
  • Try this: http://stackoverflow.com/a/7882757/268904 – James Oct 10 '12 at 10:42

5 Answers5

402

You wrote:

I've tried adding padding to the ListView itself, but then when you scroll the list it disappears under the edge of the padding.

Set ListView's clipToPadding attribute to false. This will enable padding around the ListView and scrolling to the end of the layout (and not only to the edge of the padding).

An example:

<ListView
    android:id="@+id/list_view"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:divider="@android:color/transparent"
    android:dividerHeight="10.0sp"
    android:padding="16dip"
    android:clipToPadding="false"/>

android:clipToPadding is an XML attribute of ViewGroup, the base class for layouts and views containers.

The related method call is:

public void setClipToPadding (boolean clipToPadding)
Gunnar Karlsson
  • 28,350
  • 10
  • 68
  • 71
  • 4
    Additionally, this can be made into a style or theme via `false` – pjco May 07 '13 at 16:28
  • 2
    Oh, this applies to ScrollView as well – pjco May 07 '13 at 16:35
  • 4
    Bit late to the discussion, but note that on older devices (I spotted it on some 2.3.x devices), list item views get recycled too soon. While the drawing phase knows it can draw there, the layout phase does not, so it thinks the item is off screen already. See http://stackoverflow.com/questions/15915226/when-using-cliptopadding-in-listviews-the-items-get-recycled-prematurely. – Jeffrey Klardie Jan 24 '14 at 10:13
  • @JeffreyKlardie I encounter the problem where items get recycled too soon on older device and it even makes the scrollbar resize itself on the fly, which looks really weird. @pjco I'm not sure why but setting `clipToPadding` via a style doesn't work for me, it's like if it doesn't get applied. Although, if I set it directly on the ListView it works. – ForceMagic Apr 16 '14 at 22:35
  • How to make the API 10? Why it creates a block in this API :( – Cícero Moura Oct 02 '14 at 03:42
  • 5
    Don't forget ``android:scrollbarStyle="outsideOverlay"`` so the scroll bar goes all the way through padding as well – jfcartier Nov 18 '14 at 18:56
  • Just loved your answer! Thank you so much. I was managing to work by adding blank header and footer view to listview till now. :) – Ravi Dhoriya ツ Dec 30 '15 at 05:15
20
Space padding = new Space(this);
padding.setHeight(20); // Can only specify in pixels unfortunately. No DIP :-(

ListView myListView = (ListView) findViewById(R.id.my_list_view);

myListView.addHeaderView(padding);
myListView.addFooterView(padding);

myListView.setAdapter(myAdapter);

The above ListView will have a header and footer padding of 20 pixels.

Vlad
  • 7,997
  • 3
  • 56
  • 43
Jake Wilson
  • 88,616
  • 93
  • 252
  • 370
  • 4
    Thanks for the answer! Works great!! If you want to put height in dp it can be done using DisplayMetrics: `float mDensity = getResources().getDisplayMetrics().density; int height = (int) (50 * mDensity + 0.5f); padding.setHeight(height);` – Toni Alvarez May 16 '12 at 16:23
  • 3
    Or better still, get dimens in dp at the Java level using getResources().getDimensionPixelOffset(R.dimen.some_value); – greg7gkb May 23 '12 at 04:43
  • 1
    Truly amazed at how much Android stuff I learn on StackOverflow against those I learn on the developers site – TrueCoke Feb 07 '13 at 21:33
  • 1
    Or even better `(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());` – Eugen Pechanec Sep 29 '14 at 13:04
  • 1
    There is no method "setHeight()" for View in API 23. Instead we can use "setMinimumHeight()". – KWA Jul 14 '16 at 09:30
  • `addFooterView()` needs to be set BEFORE `setAdapter()` for it to work in case anyone else is not seeing any effect :D – Zhang Jul 21 '16 at 13:21
  • The most correct answer to this question. Use `padding.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.WRAP_CONTENT, 20));` to set view height. – weaknespase Aug 28 '16 at 19:00
10

Appendage to @Jakobud's answer...

My listView was already making use of the android:divider/android:dividerHeight properties to create transparent gaps between listView items. This allowed me to simply add the android:headerDividersEnabled and android:footerDividersEnabled properties and set the Header and Footer views to new View(Activity.this).

Slight simplification for cases where you already have dividers setup in the listView.

greg7gkb
  • 4,933
  • 4
  • 41
  • 55
  • 1
    I would advise anyone where possible to use dividers instead of in item margins and paddings. Great answer – dzsonni Oct 21 '13 at 13:24
2

My solution using a ListFragment, based on the solutions by @Jakobud and @greg7gkb.

ListView listView = getListView();
listView.setDivider(null);
listView.setDividerHeight(getResources().getDimensionPixelSize(R.dimen.divider_height));
listView.setHeaderDividersEnabled(true);
listView.setFooterDividersEnabled(true);
View padding = new View(getActivity());
listView.addHeaderView(padding);
listView.addFooterView(padding);
hleinone
  • 4,470
  • 4
  • 35
  • 49
1

@Gunnar Karlsson's answer is good, but has an issue of cell views being recycled prematurely when completely behind the padding, but not yet fully off the screen. Setting clipToPadding=false is responsible for this and may or may not be fixed in a future version of android.(When using clipToPadding in ListView's the items get recycled prematurely)

I have a nice simple solution with no side effects:

  1. Add an outer (Linear or Relative) Layout to your cell_design.xml
  2. On this outer Layout add padding (i.e. 10dip) to create a "margin" around the whole cell. (N.B. only padding will work, not margin on the outer layout)
  3. On the ListView set android:dividerHeight="-10dip", the opposite of what is around the cell

Compared to the other answer, there is no need to set the divider colour. The padding at the topmost and bottommost cells will be present, and the negative divider will prevent double height dividers in between.

Community
  • 1
  • 1
James
  • 88
  • 7
  • "with no side effects" that's not entirely true. Adding another layer in your view hierarchy, especially in a listview item, means degrading the performances. – Teovald Oct 14 '14 at 16:19