Add space to the end of the RecyclerView
AndroidAndroid LayoutAndroid RecyclerviewAndroid GridlayoutAndroid Problem Overview
I have a recyclerview with a gridlayout. What I want is when the user scrolls to the end of the list (see my bad mockup), there should be an empty space with a height of 50dp, which isn't the same dimensions as my grid.
Note that this space is only visible at the very end end, as I do not want to change the layout. I could make it so that the recycerview has a margin bottom of 50dp, but I do not want to do that.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:scrollbars="vertical"
/>
</RelativeLayout>
Android Solutions
Solution 1 - Android
<RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="50dp"
android:clipToPadding="false"
/>
Solution 2 - Android
This is best achieved with an item decoration.
Here's an example that works with a LinearLayoutManager
- you'll have to adjust to suit for your Grid layout. What it does is checks each item to see if it's the last one, and if it is it adds the offset to the bottom of it. For a Grid layout, the hard part is figuring out whether your item position is in the last row or not.
// After setting layout manager, adapter, etc...
float offsetPx = getResources().getDimension(R.dimen.bottom_offset_dp);
BottomOffsetDecoration bottomOffsetDecoration = new BottomOffsetDecoration((int) offsetPx);
mRecyclerView.addItemDecoration(bottomOffsetDecoration);
...
static class BottomOffsetDecoration extends RecyclerView.ItemDecoration {
private int mBottomOffset;
public BottomOffsetDecoration(int bottomOffset) {
mBottomOffset = bottomOffset;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int dataSize = state.getItemCount();
int position = parent.getChildAdapterPosition(view);
if (dataSize > 0 && position == dataSize - 1) {
outRect.set(0, 0, 0, mBottomOffset);
} else {
outRect.set(0, 0, 0, 0);
}
}
}
For a GridLayoutManager
, inside the getItemOffsets
method you could do something similar to this to figure out if it's the last row:
GridLayoutManager grid = (GridLayoutManager)parent.getLayoutManager();
if ((dataSize - position) <= grid.getSpanCount()) {
outRect.set(0, 0, 0, mBottomOffset);
} else {
outRect.set(0, 0, 0, 0);
}
Solution 3 - Android
I had the similar issue. After reading all others replies and I found the changes in layout xml for recyclerview worked for my recycler view as expected:
android:paddingBottom="127px"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
The complete layout looks like:
<android.support.v7.widget.RecyclerView
android:id="@+id/library_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="160px"
android:layout_marginEnd="160px"
tools:listitem="@layout/library_list_item" />
For the effect of before and after see the link at androidblog.us:
Adding Space to End of Android Recylerview
Let me know how it works for you.
David
Solution 4 - Android
You can try the below code, remember "I do not test this code"
public class MyRecyclerView extends RecyclerView {
private Context context;
public MyRecyclerView(Context context) {
super(context);
this.context = context;
}
public MyRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public MyRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
View view = (View) getChildAt(getChildCount()-1);
int diff = (view.getBottom()-(getHeight()+getScrollY()+view.getTop()));
if( diff == 0 ){ // if diff is zero, then the bottom has been reached
TextView tv = new TextView(context);
tv.setHeight(dpToPx(50));
addView(tv,getChildCount());//update --> add to last
requestLayout();
}
super.onScrollChanged(l, t, oldl, oldt);
}
public int dpToPx(int dp) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
return px;
}
}
and in layout:
<your_packagae.MyRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
/>
Solution 5 - Android
Make a class name with BottomOffsetDecoration
public class BottomOffsetDecoration extends RecyclerView.ItemDecoration {
private int mBottomOffset;
public BottomOffsetDecoration(int bottomOffset) {
mBottomOffset = bottomOffset;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int dataSize = state.getItemCount();
int position = parent.getChildAdapterPosition(view);
if (dataSize > 0 && position == dataSize - 1) {
outRect.set(0, 0, 0, mBottomOffset);
} else {
outRect.set(0, 0, 0, 0);
}
}
}
then Add these line after adding adapter and layoutmanager to recyclerview
float offsetPx = getResources().getDimension(R.dimen.bottom_offset_dp);
BottomOffsetDecoration bottomOffsetDecoration = new BottomOffsetDecoration((int) offsetPx);
rv.addItemDecoration(bottomOffsetDecoration);
and for GridLayout Add these lines after assigning recyclerview layout manager
GridLayoutManager grid = (GridLayoutManager)parent.getLayoutManager();
if ((dataSize - position) <= grid.getSpanCount()) {
outRect.set(0, 0, 0, mBottomOffset);
} else {
outRect.set(0, 0, 0, 0);
}