170

I'm trying to add Padding/Margin Bottom in the last row and Padding/Margin Top in the first row. I can not do it in the item xml as it would affect all of my Children.

I have headers and children in my RecyclerView Adapter so I can not use the

   android:padding="4dp"
   android:clipToPadding="false"

I need to use it individually on the last first row of each header

souvickcse
  • 7,742
  • 5
  • 37
  • 64
RedEagle
  • 2,358
  • 3
  • 13
  • 18

10 Answers10

318

This issue is even easier to solve. You can apply necessary padding to the RecylerView itself and set clipToPadding to false, otherwise, the padding will chop off your scrolling area. Here is an example

<android.support.v7.widget.RecyclerView
    android:padding="4dp"
    android:clipToPadding="false"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

See the padding will add 4dp on all sides including top and bottom. Then the clipToPadding parameter makes sure your child items are not chopped off. Now, add 4dp padding to all sides for your child items, and you are good to go. In total you get 8dp padding on sides and between items.

C--
  • 16,393
  • 6
  • 53
  • 60
  • Yea that's how I usually do it, but I my RecyclerView is consisting of headers and each header has its own childs, that's why I need to set it programmatically to the last and first row of each header only – RedEagle Nov 17 '15 at 10:34
  • Not sure I understand. How is this related to headers inside the RecyclerView? Do you want the headers to have no padding? Even if that is the case, you can get rid of left & right padding using the same solution. – C-- Nov 17 '15 at 10:38
  • I have headers and each header has non-specific count of children so I want to add top padding/margin and the first child and bottom padding/margin at the last child of each header. – RedEagle Nov 17 '15 at 10:43
  • The only idea I had was set top and bottom margin into my header's layout but I was wondering if there's a smarter way to acheive it – RedEagle Nov 17 '15 at 10:44
  • In that case, you can simply add a fake item into the RecyclerView after your last child. That is the simplest, if not the smartest way to achieve this. :) – C-- Nov 17 '15 at 10:49
  • Saved my life. I am doing it programmatically. Which is behaving peculiarly when scrolling. – Abhi Feb 10 '23 at 05:12
118

Instead of adding padding to both the top and bottom items, You can just add the padding to the top and bottom of your RecyclerView and set the clipToPadding attribute to false.

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:paddingTop="8dp"
    android:paddingBottom="8dp" />
Collins Abitekaniza
  • 4,496
  • 2
  • 28
  • 43
  • That's the easy solution, but I have headers and childs in my RecyclerView so I can not use it – RedEagle Nov 17 '15 at 10:31
  • @RedEagle Try and see if you get the desired effect but I'm sure it works. – Collins Abitekaniza Nov 17 '15 at 10:34
  • 2
    This solution is better than the Item Decoration one. When I am using ListAdapter and submitting a different list, if the last item of the previous list did not change its position but new items were added after it, the former will keep its bottom padding even though it's not the last item in the list any more. – Ana Koridze Sep 05 '19 at 09:56
70
<android.support.v7.widget.RecyclerView
    android:id="@+id/rv_tpf"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipToPadding="false"
    android:paddingBottom="100dp" />

Add android:clipToPadding="false" and android:paddingBottom="100dp" in your recyclerview.

Minas Mina
  • 2,058
  • 3
  • 21
  • 35
darshan patel
  • 736
  • 5
  • 6
42

use ItemDecoration:

private class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpacesItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast){
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        }
        if(position == 0){
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        }
    }
}

and

//8dp as px
int space = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8,
            getResources().getDisplayMetrics()); // calculated
//int space = getResources().getDimensionPixelSize(
//    R.dimen.list_item_padding_vertical); // from resources
recyclerView.addItemDecoration(new SpacesItemDecoration(space));
snachmsm
  • 17,866
  • 3
  • 32
  • 74
  • 1
    Hey it doesn't seem like RecyclerView.ItemDecoration get the resource class any more, I just added it as an argument in the constructor. – Krtko Jun 17 '16 at 01:27
  • 4
    Goog solution! With reversed layout support: https://gist.github.com/Miha-x64/4e8754e72a1e65e3ca742744ea501f16 – Miha_x64 Jul 13 '17 at 11:44
  • 2
    this answer must be upvoted! Though Subin Sebastian's answer is working good, however, with ItemDecoration spaces are not equal. – iroiroys Aug 31 '17 at 03:04
  • 1
    but after inserting removing items it won't redraw offsets for all items – user924 Jul 09 '20 at 10:11
  • may be true, as `notifyItemInserted`/`Removed` will draw only one item/remove item and clean it's `View` leaving all other childs untouched. e.g. when some item is first on the list (drawn with top padding) and we are adding new one to top, then previously-first-currently-second item will still be padded on top... easy fix is to call `notifyDataSetChanged` (force redraw all...), more complex need some logic for recognizing that item, which was on first and/or last position, moved and then call `notifyItemChanged(newPositionOfOldFirstAndOrLastItem)` – snachmsm Jul 09 '20 at 11:44
23

Add android:clipToPadding="false" and android:paddingBottom="65dp" in your recyclerview. If you are using fab menu button and actions on recycler view cell.

<androidx.recyclerview.widget.RecyclerView
      android:id="@+id/dinner_recycler_view"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:clipToPadding="false"
      android:paddingBottom="65dp"/>
Yogesh Shinde
  • 393
  • 4
  • 11
17

I use this in kotlin to give bottom margin to last item only

override fun onBindViewHolder(holder: RecyclerView.ViewHolder(view), position: Int) {
    if (position == itemsList.lastIndex){
        val params = holder.itemView.layoutParams as FrameLayout.LayoutParams
        params.bottomMargin = 100
        holder.itemView.layoutParams = params
    }else{
        val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
        params.bottomMargin = 0
        holder.itemView.layoutParams = params
    }
  //other codes ...
}
Radesh
  • 13,084
  • 4
  • 51
  • 64
5

For some reason the old clipToPadding=false solution isn't working for me. So I added an ItemDecoration

https://gist.github.com/kassim/582888fa5960791264fc92bc41fb6bcf

public class BottomPaddingDecoration extends RecyclerView.ItemDecoration {
    private final int bottomPadding;

    public BottomPaddingDecoration(int bottomPadding) {
        this.bottomPadding = bottomPadding;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
        if (position == parent.getAdapter().getItemCount() - 1) {
            outRect.set(0, 0, 0, bottomPadding);
        }
    }
}
kassim
  • 3,880
  • 3
  • 26
  • 27
3

Java equivalent to @Radesh answer:

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    if (position == itemsList.size() - 1) {
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams();
        params.bottomMargin = 100;
        holder.itemView.setLayoutParams(params);
    } else {
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams();
        params.bottomMargin = 0;
        holder.itemView.setLayoutParams(params);
    }
}
Matthew Mitchell
  • 514
  • 4
  • 14
2

I have modified amazing answer @snachmsm answer for better and give you idea how to use properly

public class SpacesItemDecoration extends DividerItemDecoration {
    private int space;

    public SpacesItemDecoration(Context clContext,int oriantation,int space) {
        super(clContext,oriantation);
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect,view,parent,state);
        int position = parent.getChildAdapterPosition(view);
        boolean isLast = position == state.getItemCount()-1;
        if(isLast){
            outRect.bottom = space;
            outRect.top = 0; //don't forget about recycling...
        }
       /* if(position == 0){
            outRect.top = space;
            // don't recycle bottom if first item is also last
            // should keep bottom padding set above
            if(!isLast)
                outRect.bottom = 0;
        }*/
    }
}
Adil Soomro
  • 37,609
  • 9
  • 103
  • 153
sourav pandit
  • 8,647
  • 2
  • 19
  • 17
2

Long story short :

    int freeSpaceAtBottom = 100; // the bottom free space in pixels
    myRecyclerView.setClipToPadding(false);
    myRecyclerView.setPadding(0,0,0,freeSpaceAtBottom);

setClipToPadding Sets whether this list view will clip its children to its padding and resize (but not clip) any EdgeEffect to the padded region, if padding is present. (1)

ucMedia
  • 4,105
  • 4
  • 38
  • 46