Android使用gridlayoutmanager在recyclerview中的最后一个元素下面添加间距

我正在尝试添加与GridLayoutManager RecyclerView最后一个元素行下面的间距。 为了这个目的,我使用了自定义的ItemDecoration ,最后一个元素如下所示:

 public class SpaceItemDecoration extends RecyclerView.ItemDecoration { private int space; private int bottomSpace = 0; public SpaceItemDecoration(int space, int bottomSpace) { this.space = space; this.bottomSpace = bottomSpace; } public SpaceItemDecoration(int space) { this.space = space; this.bottomSpace = 0; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int childCount = parent.getChildCount(); final int itemPosition = parent.getChildAdapterPosition(view); final int itemCount = state.getItemCount(); outRect.left = space; outRect.right = space; outRect.bottom = space; outRect.top = space; if (itemCount > 0 && itemPosition == itemCount - 1) { outRect.bottom = bottomSpace; } } } 

但是这个方法的问题是它在最后一行的网格中弄乱了元素的高度。 我猜测GridLayoutManager根据剩下的空间来改变元素的高度。 什么是实现这一目标的正确方法?

这将正确地为一个LinearLayoutManager 。 只是在GridLayoutManager情况下,它的问题。

它非常有用的情况下,你有一个FAB在底部,需要在最后一行的项目滚动FAB上方,使他们可以看到。

解决这个问题的方法是重写GridLayoutManager的SpanSizeLookup。

你必须修改Activity或Fragment中的GridlayoutManager,在这里膨胀RecylerView。

 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //your code recyclerView.addItemDecoration(new PhotoGridMarginDecoration(context)); // SPAN_COUNT is the number of columns in the Grid View GridLayoutManager gridLayoutManager = new GridLayoutManager(context, SPAN_COUNT); // With the help of this method you can set span for every type of view gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { if (list.get(position).getType() == TYPE_HEADER) { // Will consume the whole width return gridLayoutManager.getSpanCount(); } else if (list.get(position).getType() == TYPE_CONTENT) { // will consume only one part of the SPAN_COUNT return 1; } else if(list.get(position).getType() == TYPE_FOOTER) { // Will consume the whole width // Will take care of spaces to be left, // if the number of views in a row is not equal to 4 return gridLayoutManager.getSpanCount(); } return gridLayoutManager.getSpanCount(); } }); recyclerView.setLayoutManager(gridLayoutManager); } 

只需添加一个填充并设置android:clipToPadding="false"

 <RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="8dp" android:clipToPadding="false" /> 

感谢这个美好的回答 !

你可以做的是添加一个空的页脚到您的回收站。 你的填充将是你的页脚的大小。

 @Override public Holder onCreateViewHolder( ViewGroup parent, int viewType) { if (viewType == FOOTER) { return new FooterHolder(); } View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); return new Holder(view); } @Override public void onBindViewHolder(final Holder holder, final int position) { //if footer if (position == items.getSize() - 1) { //do nothing return; } //do regular object bindding } @Override public int getItemViewType(int position) { return (position == items.getSize() - 1) ? FOOTER : ITEM_VIEW_TYPE_ITEM; } @Override public int getItemCount() { //add one for the footer return items.size() + 1; } 

您可以使用下面的代码来检测网格视图中的第一行和最后一行,并相应地设置顶部和底部的偏移量。

 @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { LayoutParams params = (LayoutParams) view.getLayoutParams(); int pos = params.getViewLayoutPosition(); int spanCount = mGridLayoutManager.getSpanCount(); boolean isFirstRow = pos < spanCount; boolean isLastRow = state.getItemCount() - 1 - pos < spanCount; if (isFirstRow) { outRect.top = top offset value here } if (isLastRow) { outRect.bottom = bottom offset value here } } // you also need to keep reference to GridLayoutManager to know the span count private final GridLayoutManager mGridLayoutManager; 

有了这样的事情,build议使用ItemDecoration来解决这个问题。

 public class ListSpacingDecoration extends RecyclerView.ItemDecoration { private static final int VERTICAL = OrientationHelper.VERTICAL; private int orientation = -1; private int spanCount = -1; private int spacing; public ListSpacingDecoration(Context context, @DimenRes int spacingDimen) { spacing = context.getResources().getDimensionPixelSize(spacingDimen); } public ListSpacingDecoration(int spacingPx) { spacing = spacingPx; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (orientation == -1) { orientation = getOrientation(parent); } if (spanCount == -1) { spanCount = getTotalSpan(parent); } int childCount = parent.getLayoutManager().getItemCount(); int childIndex = parent.getChildAdapterPosition(view); int itemSpanSize = getItemSpanSize(parent, childIndex); int spanIndex = getItemSpanIndex(parent, childIndex); /* INVALID SPAN */ if (spanCount < 1) return; setSpacings(outRect, parent, childCount, childIndex, itemSpanSize, spanIndex); } protected void setSpacings(Rect outRect, RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) { if (isBottomEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) { outRect.bottom = spacing; } } @SuppressWarnings("all") protected int getTotalSpan(RecyclerView parent) { RecyclerView.LayoutManager mgr = parent.getLayoutManager(); if (mgr instanceof GridLayoutManager) { return ((GridLayoutManager) mgr).getSpanCount(); } else if (mgr instanceof StaggeredGridLayoutManager) { return ((StaggeredGridLayoutManager) mgr).getSpanCount(); } else if (mgr instanceof LinearLayoutManager) { return 1; } return -1; } @SuppressWarnings("all") protected int getItemSpanSize(RecyclerView parent, int childIndex) { RecyclerView.LayoutManager mgr = parent.getLayoutManager(); if (mgr instanceof GridLayoutManager) { return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanSize(childIndex); } else if (mgr instanceof StaggeredGridLayoutManager) { return 1; } else if (mgr instanceof LinearLayoutManager) { return 1; } return -1; } @SuppressWarnings("all") protected int getItemSpanIndex(RecyclerView parent, int childIndex) { RecyclerView.LayoutManager mgr = parent.getLayoutManager(); if (mgr instanceof GridLayoutManager) { return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanIndex(childIndex, spanCount); } else if (mgr instanceof StaggeredGridLayoutManager) { return childIndex % spanCount; } else if (mgr instanceof LinearLayoutManager) { return 0; } return -1; } @SuppressWarnings("all") protected int getOrientation(RecyclerView parent) { RecyclerView.LayoutManager mgr = parent.getLayoutManager(); if (mgr instanceof LinearLayoutManager) { return ((LinearLayoutManager) mgr).getOrientation(); } else if (mgr instanceof GridLayoutManager) { return ((GridLayoutManager) mgr).getOrientation(); } else if (mgr instanceof StaggeredGridLayoutManager) { return ((StaggeredGridLayoutManager) mgr).getOrientation(); } return VERTICAL; } protected boolean isBottomEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) { if (orientation == VERTICAL) { return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex); } else { return (spanIndex + itemSpanSize) == spanCount; } } protected boolean isLastItemEdgeValid(boolean isOneOfLastItems, RecyclerView parent, int childCount, int childIndex, int spanIndex) { int totalSpanRemaining = 0; if (isOneOfLastItems) { for (int i = childIndex; i < childCount; i++) { totalSpanRemaining = totalSpanRemaining + getItemSpanSize(parent, i); } } return isOneOfLastItems && (totalSpanRemaining <= spanCount - spanIndex); } } 

我从我的原始答案复制了一个编辑,这实际上是相同的间距,但它是相同的概念。