Я пытаюсь добавить интервал ниже последней строки элемента RecyclerView
с GridLayoutManager
. Я использовал custom 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
чтобы они были видны.
android:scrollbarStyle="outsideOverlay"
Следует использовать украшение в представлении ресайклера для нижнего поля только в случае последнего элемента
recyclerView.addItemDecoration(MemberItemDecoration()) public class MemberItemDecoration extends RecyclerView.ItemDecoration { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { // only for the last one if (parent.getChildAdapterPosition(view) == parent.getAdapter().getItemCount() - 1) { outRect.bottom = 50/* set your margin here */; } } }
источник
У меня была аналогичная проблема, и я ответил на другой поток при переполнении стека. Чтобы помочь другим, кто попадет на эту страницу, я сделаю репост здесь.
Прочитав все остальные ответы, я обнаружил, что изменения в макете xml для recyclerview сработали для моего представления recycler, как и ожидалось:
android:paddingBottom="127px" android:clipToPadding="false" android:scrollbarStyle="outsideOverlay"
Полный макет выглядит так:
<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" />
Чтобы узнать об эффекте до и после, см. Ссылку на androidblog.us: Добавление места в конец Android Recylerview.
Сообщите мне, как это работает для вас.
Дэвид
источник
Вы можете использовать приведенный ниже код для обнаружения первой и последней строк в представлении сетки и установки верхнего и нижнего смещения соответственно.
@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;
источник
Что вы можете сделать, так это добавить пустой нижний колонтитул в свой recyclerview. Ваш отступ будет размером с нижний колонтитул.
@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; }
источник
В таких случаях рекомендуется решать с помощью 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); } }
Я скопировал отредактированный из моего исходного ответа здесь, который на самом деле предназначен для равного интервала, но это та же концепция.
источник
Вы можете взять DividerItemDecoration.java в качестве примера из исходного кода и заменить
for (int i = 0; i < childCount; i++)
с участием
for (int i = 0; i < childCount - 1; i++)
в drawVertical () и drawHorizontal ()
источник