Khoảng cách cột Android Recyclerview GridLayoutManager


250

Làm cách nào để bạn đặt khoảng cách cột với RecyclerView bằng GridLayoutManager? Đặt lề / phần đệm trong bố cục của tôi không có hiệu lực.


Bạn đã thử phân lớp GridLayoutManagervà ghi đè generateDefaultLayoutParams()và kin?
CommonsWare

Tôi không nghĩ, tôi đã nghĩ rằng sẽ có một phương pháp mà tôi chỉ không thấy để đặt khoảng cách cho chế độ xem dạng lưới. Tôi sẽ thử điều đó
hitch.united 15/215


Câu trả lời:


348

RecyclerViews hỗ trợ khái niệm ItemDecor : bù đắp đặc biệt và vẽ xung quanh mỗi phần tử. Như đã thấy trong câu trả lời này , bạn có thể sử dụng

public 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) {
    outRect.left = space;
    outRect.right = space;
    outRect.bottom = space;

    // Add top margin only for the first item to avoid double space between items
    if (parent.getChildLayoutPosition(view) == 0) {
        outRect.top = space;
    } else {
        outRect.top = 0;
    }
  }
}

Sau đó thêm nó qua

mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
int spacingInPixels = getResources().getDimensionPixelSize(R.dimen.spacing);
mRecyclerView.addItemDecoration(new SpacesItemDecoration(spacingInPixels));

3
Sử dụng 'outRect.top = space' và xóa 'outRect.bottom' nếu bạn không muốn gây rối với 'nếu cho vị trí đầu tiên'. ; -]
Amio.io

2
@zatziky - vâng, nếu bạn đã sử dụng phần đệm trên và dưới như một phần của RecyclerView(và sử dụng clipToPadding="false"), thì bạn có thể cấu trúc lại mọi thứ một chút. Tuy nhiên, nếu bạn không, bạn sẽ di chuyển kiểm tra nếu là lần cuối cùng (vì bạn vẫn muốn phần đệm dưới cùng trên mục cuối cùng).
ianhanniballake

18
@ianhanniballake, trong khi điều này hoạt động khi sử dụng trình quản lý bố cục nhịp đơn, nó không thành công cho trình quản lý bố cục nhiều nhịp.
Avinash R

4
Nếu bạn thực hiện theo cách này với GridLayoutManager - tất cả các mục đầu tiên của cột thứ 2, thứ 3 ... sẽ dính vào đầu (vì không có khoảng trắng). Vì vậy, tôi nghĩ rằng tốt hơn là làm .top = space / 2 và .bottom = space / 2.
Yaroslav

1
Câu trả lời này không trả lời câu hỏi ban đầu. Sự nhấn mạnh của câu hỏi là trên GridLayoutManager . Câu trả lời sẽ không hoạt động trên bố cục nhiều cột / hàng
hch

428

Mã sau hoạt động tốt và mỗi cột có cùng chiều rộng:

public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;
    private boolean includeEdge;

    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // item position
        int column = position % spanCount; // item column

        if (includeEdge) {
            outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
            outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

            if (position < spanCount) { // top edge
                outRect.top = spacing;
            }
            outRect.bottom = spacing; // item bottom
        } else {
            outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
            outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
            if (position >= spanCount) {
                outRect.top = spacing; // item top
            }
        }
    }
}

Sử dụng

1. không có cạnh

nhập mô tả hình ảnh ở đây

int spanCount = 3; // 3 columns
int spacing = 50; // 50px
boolean includeEdge = false;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));

2. với cạnh

nhập mô tả hình ảnh ở đây

int spanCount = 3; // 3 columns
int spacing = 50; // 50px
boolean includeEdge = true;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));

12
Hoạt động trừ khi bạn có các mục có nhiều nhịp, như tiêu đề.
Matthew

8
Câu trả lời chính xác; một mẹo: khoảng cách là trong px (vì vậy bạn có thể chuyển đổi dp thành px bằng Math.round (someDpValue * getResource (). getDisplayMetrics (). mật độ))
Kevin Lee

1
Nó hoạt động tốt nhưng tôi gặp sự cố, tôi đang sử dụng GridLayoutManager với spanCount là 2 (mặc định) nhưng người dùng có thể thay đổi spanCount để khi spanCount thay đổi từ vị trí mặc định, có một phần đệm rõ ràng hơn trên một số vị trí như nếu spanCount sẽ 3 đệm / lề trên 2,3 8,9 12,13, v.v.
Haris Qureshi

2
Hoạt động tuyệt vời! Nhưng tôi có một số vấn đề với StaggeredGridLayoutManager. Đôi khi lề ngang của imgur.com/XVutH5u khác nhau.
Ufkoku

2
Điều này không hoạt động khi bố trí là rtl (cho 2 cột trở lên). hiện tại không gian giữa các cột không đúng khi ở chế độ rtl. bạn cần thay thế: outRect.left bằng outRect.right khi nó ở trong rtl.
Masoud Mohammadi

83

Sau đây là giải pháp đơn giản từng bước nếu bạn muốn khoảng cách bằng nhau xung quanh các mục và kích thước mục bằng nhau.

Mục OffersetDecor

public class ItemOffsetDecoration extends RecyclerView.ItemDecoration {

    private int mItemOffset;

    public ItemOffsetDecoration(int itemOffset) {
        mItemOffset = itemOffset;
    }

    public ItemOffsetDecoration(@NonNull Context context, @DimenRes int itemOffsetId) {
        this(context.getResources().getDimensionPixelSize(itemOffsetId));
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
            RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.set(mItemOffset, mItemOffset, mItemOffset, mItemOffset);
    }
}

Thực hiện

Trong mã nguồn của bạn, thêm ItemOffsetDecorationvào RecyclerView. giá trị offset Mục của bạn phải bằng một nửa kích thước của giá trị thực bạn muốn thêm dưới dạng khoảng trắng giữa các mục.

mRecyclerView.setLayoutManager(new GridLayoutManager(context, NUM_COLUMNS);
ItemOffsetDecoration itemDecoration = new ItemOffsetDecoration(context, R.dimen.item_offset);
mRecyclerView.addItemDecoration(itemDecoration);

Ngoài ra, đặt giá trị offset của mục làm phần đệm cho nó RecyclerViewvà chỉ định android:clipToPadding=false.

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerview_grid"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:padding="@dimen/item_offset"/>

Hoàn hảo, nó đơn giản và hiệu quả.
B.shruti

28

Thử cái này. Nó sẽ chăm sóc khoảng cách bằng nhau xung quanh. Hoạt động cả với List, Grid và StaggeredGrid.

Đã chỉnh sửa

Mã được cập nhật sẽ xử lý hầu hết các trường hợp góc với các nhịp, hướng, v.v. Lưu ý rằng nếu sử dụng setSpanSizeLookup () với GridLayoutManager, nên cài đặt setSpanIndexCacheEnabled () vì lý do hiệu suất.

Lưu ý, có vẻ như với StaggeredGrid, dường như có một lỗi mà chỉ số của trẻ em trở nên khó hiểu và khó theo dõi nên mã dưới đây có thể không hoạt động tốt với StaggeredGridLayoutManager.

public class ListSpacingDecoration extends RecyclerView.ItemDecoration {

  private static final int VERTICAL = OrientationHelper.VERTICAL;

  private int orientation = -1;
  private int spanCount = -1;
  private int spacing;
  private int halfSpacing;


  public ListSpacingDecoration(Context context, @DimenRes int spacingDimen) {

    spacing = context.getResources().getDimensionPixelSize(spacingDimen);
    halfSpacing = spacing / 2;
  }

  public ListSpacingDecoration(int spacingPx) {

    spacing = spacingPx;
    halfSpacing = spacing / 2;
  }

  @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) {

    outRect.top = halfSpacing;
    outRect.bottom = halfSpacing;
    outRect.left = halfSpacing;
    outRect.right = halfSpacing;

    if (isTopEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
        outRect.top = spacing;
    }

    if (isLeftEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
        outRect.left = spacing;
    }

    if (isRightEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
        outRect.right = spacing;
    }

    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 isLeftEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {

    if (orientation == VERTICAL) {

        return spanIndex == 0;

    } else {

        return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
    }
  }

  protected boolean isRightEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {

    if (orientation == VERTICAL) {

        return (spanIndex + itemSpanSize) == spanCount;

    } else {

        return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
    }
  }

  protected boolean isTopEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {

    if (orientation == VERTICAL) {

        return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);

    } else {

        return spanIndex == 0;
    }
  }

  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 isFirstItemEdgeValid(boolean isOneOfFirstItems, RecyclerView parent, int childIndex) {

    int totalSpanArea = 0;
    if (isOneOfFirstItems) {
        for (int i = childIndex; i >= 0; i--) {
            totalSpanArea = totalSpanArea + getItemSpanSize(parent, i);
        }
    }

    return isOneOfFirstItems && totalSpanArea <= 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);
  }
}

Hy vọng nó giúp.


1
Tôi đã có nhịp gấp đôi chỉ sau dòng sản phẩm đầu tiên. Điều này xảy ra vì Parent.getChildCount () trả về 1 cho mục đầu tiên, 2 cho mục thứ hai và cứ thế. Vì vậy, tôi đề nghị thêm không gian vào các mục của cạnh trên như: outRect.top = child Index <spanCount? spacesInPixels: 0; Và thêm không gian dưới cùng cho mỗi mục: outRect.bottom = spacesInPixels;
IvanP

Tại thời điểm cuộn RecyclerView, khoảng cách thay đổi.
Yugesh

3
Tôi nghĩ nên thay đổi Parent.getChildCount () thành "Parent.getLayoutManager (). GetItemCount ()". Ngoài ra, hàm isBottomEdge cần được thay đổi thành "return child Index> = childCount - spanCount + span Index". Sau khi thay đổi chúng, tôi có khoảng cách bằng nhau. Nhưng xin lưu ý rằng giải pháp này không cung cấp cho tôi kích thước mục bằng nhau nếu số lượng nhịp lớn hơn 2 vì giá trị offset khác nhau tùy theo vị trí.
yqritc

1
@yqritc cảm ơn vì đã nuôi dưỡng cha mẹ.getChildCount (). Tôi đã cập nhật câu trả lời của mình để sử dụng cha mẹ.getLayoutManager (). GetItemCount ()
Pirdad Sakhizada

2
Điều này làm việc rất tốt ra khỏi hộp ngay cả với các nhịp thay đổi, xin chúc mừng và cảm ơn bạn!
Pierre-Luc Paour

21

Đoạn mã sau sẽ xử lý StaggeredGridLayoutManager, GridLayoutManager và linearLayoutManager.

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {

    private int halfSpace;

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

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

        if (parent.getPaddingLeft() != halfSpace) {
            parent.setPadding(halfSpace, halfSpace, halfSpace, halfSpace);
            parent.setClipToPadding(false);
        }

        outRect.top = halfSpace;
        outRect.bottom = halfSpace;
        outRect.left = halfSpace;
        outRect.right = halfSpace;
    }
}

Sau đó sử dụng nó

mRecyclerView.addItemDecoration(new SpacesItemDecoration(mMargin));

1
Đây là một trong những đơn giản nhất. Một điều quan trọng là bạn cũng phải thêm phần đệm cho cha mẹ trong xml. Trong trường hợp của tôi, nó hoạt động theo cách đó. Cảm ơn.
Samir

Thực SpaceItemDecorationtế thêm phần đệm cho cha mẹ (khung nhìn của trình tái chế).
Đánh dấu Hetherington

chỉ có phần halfSpaceđệm xuất hiện (ở phía bên phải) khi tôi chưa đặt phần đệm cho cha mẹ trong xml
Samir

Nó chỉ bị thiếu ở phía bên phải? Có thể là bạn có một nửa không gian được đặt là phần bên trái ở bên trái đã có trong xml và mã này chỉ kiểm tra xem phần đệm bên trái có được đặt trên RecyclerView hay không.
Đánh dấu Hetherington

Vâng, tôi không có bộ đệm nào trong xml.
Samir

11

Đây là một giải pháp không yêu cầu "spanCount" (số lượng cột) tôi sử dụng vì tôi sử dụng GridAutofitLayoutManager (tính toán số lượng cột theo kích thước ô yêu cầu)

(hãy cẩn thận rằng điều này sẽ chỉ hoạt động trên GridLayoutManager )

public class GridSpacesItemDecoration extends RecyclerView.ItemDecoration {
    private final boolean includeEdge;
    private int spacing;


    public GridSpacesItemDecoration(int spacing, boolean includeEdge) {
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (parent.getLayoutManager() instanceof GridLayoutManager) {
            GridLayoutManager layoutManager = (GridLayoutManager)parent.getLayoutManager();
            int spanCount = layoutManager.getSpanCount();
            int position = parent.getChildAdapterPosition(view); // item position
            int column = position % spanCount; // item column

            if (includeEdge) {
                outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }

        }

    }
}

Dưới đây là GridAutofitLayoutManager được bất cứ ai quan tâm:

public class GridAutofitLayoutManager extends GridLayoutManager {
    private int mColumnWidth;
    private boolean mColumnWidthChanged = true;

    public GridAutofitLayoutManager(Context context, int columnWidth)
    {
        /* Initially set spanCount to 1, will be changed automatically later. */
        super(context, 1);
        setColumnWidth(checkedColumnWidth(context, columnWidth));
    }

    public GridAutofitLayoutManager(Context context,int unit, int columnWidth)
    {
        /* Initially set spanCount to 1, will be changed automatically later. */
        super(context, 1);
        int pixColumnWidth = (int) TypedValue.applyDimension(unit, columnWidth, context.getResources().getDisplayMetrics());
        setColumnWidth(checkedColumnWidth(context, pixColumnWidth));
    }

    public GridAutofitLayoutManager(Context context, int columnWidth, int orientation, boolean reverseLayout)
    {
        /* Initially set spanCount to 1, will be changed automatically later. */
        super(context, 1, orientation, reverseLayout);
        setColumnWidth(checkedColumnWidth(context, columnWidth));
    }

    private int checkedColumnWidth(Context context, int columnWidth)
    {
        if (columnWidth <= 0)
        {
            /* Set default columnWidth value (48dp here). It is better to move this constant
            to static constant on top, but we need context to convert it to dp, so can't really
            do so. */
            columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
                    context.getResources().getDisplayMetrics());
        }
        return columnWidth;
    }

    public void setColumnWidth(int newColumnWidth)
    {
        if (newColumnWidth > 0 && newColumnWidth != mColumnWidth)
        {
            mColumnWidth = newColumnWidth;
            mColumnWidthChanged = true;
        }
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
    {
        int width = getWidth();
        int height = getHeight();
        if (mColumnWidthChanged && mColumnWidth > 0 && width > 0 && height > 0)
        {
            int totalSpace;
            if (getOrientation() == VERTICAL)
            {
                totalSpace = width - getPaddingRight() - getPaddingLeft();
            }
            else
            {
                totalSpace = height - getPaddingTop() - getPaddingBottom();
            }
            int spanCount = Math.max(1, totalSpace / mColumnWidth);
            setSpanCount(spanCount);

            mColumnWidthChanged = false;
        }
        super.onLayoutChildren(recycler, state);
    }
}

Cuối cùng:

mDevicePhotosView.setLayoutManager(new GridAutofitLayoutManager(getContext(), getResources().getDimensionPixelSize(R.dimen.item_size)));
mDevicePhotosView.addItemDecoration(new GridSpacesItemDecoration(Util.dpToPx(getContext(), 2),true));

Chào. Điều này hoạt động tuyệt vời nhưng tôi đang sử dụng một tiêu đề với giải pháp của bạn. Bạn có thể đề nghị làm thế nào có thể đạt được tiêu đề toàn chiều rộng?
Ajeet

vui lòng bạn có thể kiểm tra vị trí với trình quản lý bố cục như sau, layoutManager.getPosition(view)sau đó kiểm tra xem vị trí có bằng 0 không, đó sẽ là tiêu đề của bạn .. ngoài ra, cách này sẽ cho phép bạn thêm một tiêu đề khác vào bất kỳ vị trí nào bạn muốn :)
Mina Samir

9

Chỉ có một giải pháp dễ dàng, đó là bạn có thể nhớ và thực hiện bất cứ khi nào cần. Không có lỗi, không có tính toán điên rồ. Đặt lề cho bố cục thẻ / vật phẩm và đặt cùng kích thước với phần đệm vào RecyclerView:

item_layout.xml

<CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:margin="10dp">

Activity_layout.xml

<RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"/>

CẬP NHẬT: nhập mô tả hình ảnh ở đây


Nó hoạt động tốt! bạn có thể giải thích về vấn đề này không?
elyar abad

Cảm ơn bạn rất nhiều! Tôi đã tìm kiếm một số lý do kỹ thuật tại sao cần có sự hợp tác giữa phần đệm của người tái chế và phần lề của vật phẩm. Bất cứ cách nào bạn đã làm rất nhiều cho tôi. . .
elyar abad

7

Nếu bạn muốn CỐ ĐỊNH kích thước của RecyclerViewmặt hàng của bạn trong tất cả các thiết bị. Bạn có thể làm như thế này

public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

    private int mSpanCount;
    private float mItemSize;

    public GridSpacingItemDecoration(int spanCount, int itemSize) {
        this.mSpanCount = spanCount;
        mItemSize = itemSize;
    }

    @Override
    public void getItemOffsets(final Rect outRect, final View view, RecyclerView parent,
            RecyclerView.State state) {
        final int position = parent.getChildLayoutPosition(view);
        final int column = position % mSpanCount;
        final int parentWidth = parent.getWidth();
        int spacing = (int) (parentWidth - (mItemSize * mSpanCount)) / (mSpanCount + 1);
        outRect.left = spacing - column * spacing / mSpanCount;
        outRect.right = (column + 1) * spacing / mSpanCount;

        if (position < mSpanCount) {
            outRect.top = spacing;
        }
        outRect.bottom = spacing;
    }
}

recyclerview_item.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="@dimen/recycler_view_item_width" 
    ...
    >
    ...
</LinearLayout>

dimens.xml

 <dimen name="recycler_view_item_width">60dp</dimen>

Hoạt động

int numberOfColumns = 3;
mRecyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
mRecyclerView.setAdapter(...);
mRecyclerView.addItemDecoration(new GridSpacingItemDecoration(3,
        getResources().getDimensionPixelSize(R.dimen.recycler_view_item_width)));

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


Nó sẽ hoạt động theo kích thước màn hình có nghĩa là cách nó hiển thị trên màn hình 5 inch, chúng trông giống nhau trên các kích thước màn hình khác?
Sunil

Kích thước của mục sẽ cố định nhưng không gian giữa các mục có thể khác nhau, bạn có thể xem quá 2 hình ảnh ở trên để hiểu
Phan Văn Linh

Chúng trông khác nhau trên các kích thước màn hình khác nhau. Cách khác nhau nhưng hoạt động cảm ơn bạn
Sunil

6

Câu trả lời được chọn là gần như hoàn hảo, nhưng tùy thuộc vào không gian, chiều rộng của vật phẩm có thể không bằng nhau. (Trong trường hợp của tôi nó rất quan trọng). Vì vậy, tôi đã kết thúc với mã này làm tăng không gian một chút, vì vậy các mục đều có cùng chiều rộng.

   class GridSpacingItemDecoration(private val columnCount: Int, @Px preferredSpace: Int, private val includeEdge: Boolean): RecyclerView.ItemDecoration() {

    /**
     * In this algorithm space should divide by 3 without remnant or width of items can have a difference
     * and we want them to be exactly the same
     */
    private val space = if (preferredSpace % 3 == 0) preferredSpace else (preferredSpace + (3 - preferredSpace % 3))

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
        val position = parent.getChildAdapterPosition(view)

        if (includeEdge) {

            when {
                position % columnCount == 0 -> {
                    outRect.left = space
                    outRect.right = space / 3
                }
                position % columnCount == columnCount - 1 -> {
                    outRect.right = space
                    outRect.left = space / 3
                }
                else -> {
                    outRect.left = space * 2 / 3
                    outRect.right = space * 2 / 3
                }
            }

            if (position < columnCount) {
                outRect.top = space
            }

            outRect.bottom = space

        } else {

            when {
                position % columnCount == 0 -> outRect.right = space * 2 / 3
                position % columnCount == columnCount - 1 -> outRect.left = space * 2 / 3
                else -> {
                    outRect.left = space / 3
                    outRect.right = space / 3
                }
            }

            if (position >= columnCount) {
                outRect.top = space
            }
        }
    }

}

Tôi sẽ thêm các dòng sau, nếu ai đó thích tôi sử dụng GridLayoutManager với spanCount = 1 columnCount == 1 -> { outRect.left = space outRect.right = space }
massivemadness

5

Đã sao chép mã @edwardaa được cung cấp và tôi làm cho nó hoàn hảo để hỗ trợ RTL:

public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
    private int spanCount;
    private int spacing;
    private boolean includeEdge;
    private int headerNum;
    private boolean isRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL;

    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge, int headerNum) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
        this.headerNum = headerNum;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view) - headerNum; // item position
        if (position >= 0) {
            int column = position % spanCount; // item column
            if(isRtl) {
                column = spanCount - 1 - column;
            }
            if (includeEdge) {
                outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }
        } else {
            outRect.left = 0;
            outRect.right = 0;
            outRect.top = 0;
            outRect.bottom = 0;
        }
    }
}

mọi người đều có thể sao chép mã từ gist.github.com/xingstarx/f2525ef32b04a5e67fecc5c0b5c4b939
Xingxing

4

Các câu trả lời ở trên đã làm rõ các cách để thiết lập xử lý lề GridLayoutManager và linearLayoutManager.

Nhưng đối với StaggeredGridLayoutManager, câu trả lời của Pirdad Sakhizada nói: "Nó có thể không hoạt động tốt với StaggeredGridLayoutManager". Nó sẽ là vấn đề về IndexOfSpan.

Bạn có thể lấy nó bằng cách này:

private static class MyItemDecoration extends RecyclerView.ItemDecoration {
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int index = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
    }
}

4
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;
    private boolean includeEdge;

    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
        int column = params.getSpanIndex();

        if (includeEdge) {
            outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
            outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

            if (position < spanCount) { // top edge
                outRect.top = spacing;
            }
            outRect.bottom = spacing; // item bottom
        } else {
            outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
            outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
            if (position >= spanCount) {
                outRect.top = spacing; // item top
            }
        }
    }
}

Khác một chút so với câu trả lời của edwardaa, sự khác biệt là cách xác định cột, bởi vì trong các trường hợp như các mục có độ cao khác nhau, cột không thể được xác định chỉ bằng% spanCount


4
class VerticalGridSpacingDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() {

  override fun getItemOffsets(
    outRect: Rect,
    view: View,
    parent: RecyclerView,
    state: State
  ) {
    val layoutManager = parent.layoutManager as? GridLayoutManager
    if (layoutManager == null || layoutManager.orientation != VERTICAL) {
      return super.getItemOffsets(outRect, view, parent, state)
    }

    val spanCount = layoutManager.spanCount
    val position = parent.getChildAdapterPosition(view)
    val column = position % spanCount
    with(outRect) {
      left = if (column == 0) 0 else spacing / 2
      right = if (column == spanCount.dec()) 0 else spacing / 2
      top = if (position < spanCount) 0 else spacing
    }
  }
}

3

Đây là sửa đổi của tôi trong SpacesItemDecorationđó có thể mất numOfColumskhông gian bằng nhau ở trên, dưới, trái và phải .

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

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

    @Override
    public void getItemOffsets(Rect outRect, View view,
                               RecyclerView parent, RecyclerView.State state) {

        //outRect.right = space;
        outRect.bottom = space;
        //outRect.left = space;

        //Log.d("ttt", "item position" + parent.getChildLayoutPosition(view));
        int position=parent.getChildLayoutPosition(view);

        if(mNumCol<=2) {
            if (position == 0) {
                outRect.left = space;
                outRect.right = space / 2;
            } else {
                if ((position % mNumCol) != 0) {
                    outRect.left = space / 2;
                    outRect.right = space;
                } else {
                    outRect.left = space;
                    outRect.right = space / 2;
                }
            }
        }else{
            if (position == 0) {
                outRect.left = space;
                outRect.right = space / 2;
            } else {
                if ((position % mNumCol) == 0) {
                    outRect.left = space;
                    outRect.right = space/2;
                } else if((position % mNumCol) == (mNumCol-1)){
                    outRect.left = space/2;
                    outRect.right = space;
                }else{
                    outRect.left=space/2;
                    outRect.right=space/2;
                }
            }

        }

        if(position<mNumCol){
            outRect.top=space;
        }else{
            outRect.top=0;
        }
        // Add top margin only for the first item to avoid double space between items
        /*
        if (parent.getChildLayoutPosition(view) == 0 ) {

        } else {
            outRect.top = 0;
        }*/
    }
}

và sử dụng mã dưới đây trên logic của bạn.

recyclerView.addItemDecoration(new SpacesItemDecoration(spacingInPixels, numCol));

2

Có một giải pháp rất đơn giản và linh hoạt cho vấn đề này khi chỉ sử dụng XML, hoạt động trên mọi Trình quản lý bố cục.

Giả sử bạn muốn có khoảng cách bằng nhau của X (ví dụ 8dp).

  1. Gói mục CardView của bạn trong Bố cục khác

  2. Cung cấp cho Bố cục bên ngoài một phần đệm X / 2 (4dp)

  3. Làm cho nền Bố cục bên ngoài trong suốt

...

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:background="@android:color/transparent"
    android:padding="4dip">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.CardView>

</LinearLayout>
  1. Cung cấp cho Recycler của bạn một phần đệm X / 2 (4dp)

...

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

và đó là nó. Bạn có khoảng cách hoàn hảo của X (8dp).


2

Dành cho những người gặp vấn đề với staggeredLayoutManager (như https://imgur.com/XVutH5u )

Các phương thức của recyclerView:

getChildAdapterPosition(view)
getChildLayoutPosition(view)

đôi khi trả về -1 dưới dạng chỉ mục để chúng tôi có thể gặp rắc rối khi đặt itemDecor. Giải pháp của tôi là ghi đè phương thức của ItemDecoration không dùng nữa:

public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent)

thay vì người mới:

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)

như thế này:

recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
            @Override
            public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
                TheAdapter.VH vh = (TheAdapter.VH) recyclerView.findViewHolderForAdapterPosition(itemPosition);
                View itemView = vh.itemView;    //itemView is the base view of viewHolder
                //or instead of the 2 lines above maybe it's possible to use  View itemView = layoutManager.findViewByPosition(itemPosition)  ... NOT TESTED

                StaggeredGridLayoutManager.LayoutParams itemLayoutParams = (StaggeredGridLayoutManager.LayoutParams) itemView.getLayoutParams();

                int spanIndex = itemLayoutParams.getSpanIndex();

                if (spanIndex == 0)
                    ...
                else
                    ...
            }
        });

Có vẻ như để làm việc cho tôi cho đến nay :)


Người đàn ông trả lời tuyệt vời! Hoạt động cho tất cả các trường hợp, bao gồm cả GridLayoutManager không đối xứng, nơi bạn có một mục tiêu đề giữa các mục. Cảm ơn!
Shirane85

2

Các câu trả lời cho câu hỏi này có vẻ phức tạp hơn mức cần thiết. Đây là của tôi về điều này.

Giả sử bạn muốn khoảng cách 1dp giữa các mục lưới. Làm như sau:

  1. Thêm một phần đệm 0,5dp vào mỗi mục
  2. Thêm phần đệm -0,5dp vào RecyclView
  3. Đó là nó! :)

1

Điều này sẽ làm việc RecyclerViewvới tiêu đề là tốt.

public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;
    private boolean includeEdge;
    private int headerNum;

    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge, int headerNum) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
        this.headerNum = headerNum;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view) - headerNum; // item position

        if (position >= 0) {
            int column = position % spanCount; // item column

            if (includeEdge) {
                outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }
        } else {
            outRect.left = 0;
            outRect.right = 0;
            outRect.top = 0;
            outRect.bottom = 0;
        }
    }
    }
}

Tiêu đềNum là gì?
Tim Kranen

1

Câu trả lời của yqritc đã làm việc hoàn hảo cho tôi. Tôi đã sử dụng Kotlin tuy nhiên ở đây tương đương với điều đó.

class ItemOffsetDecoration : RecyclerView.ItemDecoration  {

    // amount to add to padding
    private val _itemOffset: Int

    constructor(itemOffset: Int) {
        _itemOffset = itemOffset
    }

    constructor(@NonNull context: Context, @DimenRes itemOffsetId: Int){
       _itemOffset = context.resources.getDimensionPixelSize(itemOffsetId)
    }

    /**
     * Applies padding to all sides of the [Rect], which is the container for the view
     */
    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView,state: RecyclerView.State) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.set(_itemOffset, _itemOffset, _itemOffset, _itemOffset)
    }
}

Mọi thứ khác là như nhau.


1

Đối với người dùng StaggeredGridLayoutManager , hãy cẩn thận, rất nhiều câu trả lời ở đây bao gồm câu trả lời được bình chọn nhiều nhất sẽ tính toán cột mục với mã dưới đây:

int column = position % spanCount

giả định rằng các vật phẩm thứ 1 / thứ 5/5 / .. luôn được đặt ở phía bên trái và thứ 2/4/6 / .. các vật phẩm luôn được đặt ở phía bên phải. Là giả định này luôn luôn đúng? Không.

Giả sử mục thứ 1 của bạn cao 100dp và thứ 2 chỉ 50dp, hãy đoán xem mục thứ 3 của bạn nằm ở đâu, bên trái hay bên phải?


0

Tôi đã kết thúc việc đó như thế với RecyclerView của mình với GridLayoutManager và HeaderView .

Trong đoạn mã dưới đây, tôi đặt khoảng trống 4dp giữa mỗi mục (2dp xung quanh mỗi mục đơn và phần đệm 2dp xung quanh toàn bộ recyclerview).

layout.xml

<android.support.v7.widget.RecyclerView
    android:id="@+id/recycleview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="2dp" />

mảnh / hoạt động

GridLayoutManager manager = new GridLayoutManager(getContext(), 3);
recyclerView.setLayoutManager(manager);
int spacingInPixels = Utils.dpToPx(2);
recyclerView.addItemDecoration(new SpacesItemDecoration(spacingInPixels));

SpaceItemDecor.java

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {

    private int mSpacing;

    public SpacesItemDecoration(int spacing) {
        mSpacing = spacing;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView recyclerView, RecyclerView.State state) {
        outRect.left = mSpacing;
        outRect.top = mSpacing;
        outRect.right = mSpacing;
        outRect.bottom = mSpacing;
    }
}

Utils.java

public static int dpToPx(final float dp) {
    return Math.round(dp * (Resources.getSystem().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
}

0

Để thực hiện giải pháp https://stackoverflow.com/a/29905000/1649371 (ở trên), tôi đã phải sửa đổi các phương thức sau (và tất cả các cuộc gọi tiếp theo)

@SuppressWarnings("all")
protected int getItemSpanSize(RecyclerView parent, View view, int childIndex) {

    RecyclerView.LayoutManager mgr = parent.getLayoutManager();
    if (mgr instanceof GridLayoutManager) {
        return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanSize(childIndex);
    } else if (mgr instanceof StaggeredGridLayoutManager) {
        return ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).isFullSpan() ? spanCount : 1;
    } else if (mgr instanceof LinearLayoutManager) {
        return 1;
    }

    return -1;
}

@SuppressWarnings("all")
protected int getItemSpanIndex(RecyclerView parent, View view, int childIndex) {

    RecyclerView.LayoutManager mgr = parent.getLayoutManager();
    if (mgr instanceof GridLayoutManager) {
        return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanIndex(childIndex, spanCount);
    } else if (mgr instanceof StaggeredGridLayoutManager) {
        return ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
    } else if (mgr instanceof LinearLayoutManager) {
        return 0;
    }

    return -1;
}


0

Nếu bạn có một công tắc bật tắt chuyển đổi giữa danh sách thành lưới, đừng quên gọi recyclerView.removeItemDecoration()trước khi đặt bất kỳ trang trí Mục mới nào. Nếu không thì các tính toán mới cho khoảng cách sẽ không chính xác.


Một cái gì đó như thế này.

        recyclerView.removeItemDecoration(gridItemDecorator)
        recyclerView.removeItemDecoration(listItemDecorator)
        if (showAsList){
            recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
            recyclerView.addItemDecoration(listItemDecorator)
        }
        else{
            recyclerView.layoutManager = GridLayoutManager(this, spanCount)
            recyclerView.addItemDecoration(gridItemDecorator)
        }

0

Nếu bạn đang sử dụng Tiêu đề với GridLayoutManager, hãy sử dụng mã này được viết bằng kotlin để tạo khoảng cách giữa các lưới:

inner class SpacesItemDecoration(itemSpace: Int) : RecyclerView.ItemDecoration() {
    var space: Int = itemSpace

    override fun getItemOffsets(outRect: Rect?, view: View?, parent: RecyclerView?, state: RecyclerView.State?) {
        super.getItemOffsets(outRect, view, parent, state)
        val position = parent!!.getChildAdapterPosition(view)
        val viewType = parent.adapter.getItemViewType(position)
       //check to not to set any margin to header item 
        if (viewType == GridViewAdapter.TYPE_HEADER) {
            outRect!!.top = 0
            outRect.left = 0
            outRect.right = 0
            outRect.bottom = 0
        } else {
            outRect!!.left = space
            outRect.right = space
            outRect.bottom = space

            if (parent.getChildLayoutPosition(view) == 0) {
                outRect.top = space
            } else {
                outRect.top = 0
            }
        }
    }
    }

Và vượt qua ItemDecorationđể recyclerviewnhư

mIssueGridView.addItemDecoration(SpacesItemDecoration(10))

0

Khi sử dụng CardView cho trẻ em, vấn đề về khoảng cách giữa các mục có thể được giải quyết bằng cách cài đặt ứng dụng: cardUseCompatPadding thành true.

Đối với lề lớn hơn phóng to độ cao mục. CardElevation là tùy chọn (sử dụng giá trị mặc định).

<androidx.cardview.widget.CardView
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:cardUseCompatPadding="true"
    app:cardElevation="2dp">

-1

cảm ơn câu trả lời của edwardaa https://stackoverflow.com/a/30701422/2227031

Một điểm khác cần lưu ý là:

nếu tổng khoảng cách và tổng số itemWidth không bằng chiều rộng màn hình, bạn cũng cần điều chỉnh itemWidth, ví dụ, trên bộ điều hợp trên phương thứcBindViewHolder

Utils.init(_mActivity);
int width = 0;
if (includeEdge) {
    width = ScreenUtils.getScreenWidth() - spacing * (spanCount + 1);
} else {
    width = ScreenUtils.getScreenWidth() - spacing * (spanCount - 1);
}
int itemWidth = width / spanCount;

ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) holder.imageViewAvatar.getLayoutParams();
// suppose the width and height are the same
layoutParams.width = itemWidth;
layoutParams.height = itemWidth;
holder.imageViewAvatar.setLayoutParams(layoutParams);

-1

Một phiên bản Kotlin tôi đã thực hiện dựa trên câu trả lời tuyệt vời của edwardaa

class RecyclerItemDecoration(private val spanCount: Int, private val spacing: Int) : RecyclerView.ItemDecoration() {

  override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {

    val spacing = Math.round(spacing * parent.context.resources.displayMetrics.density)
    val position = parent.getChildAdapterPosition(view)
    val column = position % spanCount

    outRect.left = spacing - column * spacing / spanCount
    outRect.right = (column + 1) * spacing / spanCount

    outRect.top = if (position < spanCount) spacing else 0
    outRect.bottom = spacing
  }

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.