การเว้นวรรคคอลัมน์ Android Recyclerview GridLayoutManager


251

คุณจะตั้งระยะห่างคอลัมน์ด้วย RecyclerView โดยใช้ GridLayoutManager ได้อย่างไร การตั้งค่าระยะขอบ / ช่องว่างภายในเค้าโครงของฉันไม่มีผลใด ๆ


คุณเคยลอง subclassing GridLayoutManagerและ overriding generateDefaultLayoutParams()และ kin บ้างไหม?
CommonsWare

ฉันไม่ได้ฉันคิดว่าจะมีวิธีที่ฉันเพิ่งไม่เห็นที่จะตั้งระยะห่างในมุมมองกริดเหมือน ฉันจะลองดู
hitch.united


คำตอบ:


348

RecyclerViews สนับสนุนแนวคิดของItemDecoration : ออฟเซ็ตพิเศษและการวาดภาพรอบ ๆ แต่ละองค์ประกอบ เท่าที่เห็นในคำตอบนี้คุณสามารถใช้

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;
    }
  }
}

จากนั้นเพิ่มผ่าน

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

3
ใช้ 'outRect.top = space' และลบ 'outRect.bottom' หากคุณไม่ต้องการยุ่งกับ 'ถ้าเป็นตำแหน่งแรก' ; -]
Amio.io

2
@zatziky - อ๋อถ้าคุณใช้ช่องว่างด้านบนและด้านล่างเป็นส่วนหนึ่งของRecyclerView(และใช้clipToPadding="false") แล้วคุณสามารถปรับโครงสร้างสิ่งต่าง ๆ เล็กน้อย หากคุณไม่ทำเช่นนั้นคุณจะต้องย้ายเช็คถ้าเป็นครั้งสุดท้าย (เพราะคุณยังต้องการให้ช่องว่างด้านล่างของรายการสุดท้าย)
ianhanniballake

18
@ianhanniballake ในขณะที่มันใช้งานได้เมื่อใช้ตัวจัดการเลย์เอาต์แบบขยายเดียวมันล้มเหลวสำหรับตัวจัดการเลย์เอาต์แบบหลายช่วง
Avinash R

4
หากคุณทำเช่นนี้กับ GridLayoutManager - รายการแรกทั้งหมดของคอลัมน์ที่ 2, 3 ... nth จะติดอยู่ด้านบน (เพราะไม่มีที่ว่าง) ดังนั้นฉันคิดว่ามันจะดีกว่าที่จะทำ. top = space / 2 และ. bottom = space / 2
Yaroslav

1
คำตอบนี้ไม่ตอบคำถามเดิม GridLayoutManager ความสำคัญของคำถามที่อยู่ใน คำตอบจะไม่ทำงานในรูปแบบหลายคอลัมน์ / แถว
23435

428

รหัสต่อไปนี้ทำงานได้ดีและแต่ละคอลัมน์มีความกว้างเท่ากัน:

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
            }
        }
    }
}

การใช้

1. ไม่มีขอบ

ป้อนคำอธิบายรูปภาพที่นี่

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

2. มีขอบ

ป้อนคำอธิบายรูปภาพที่นี่

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

12
ใช้งานได้เว้นแต่คุณจะมีรายการที่มีช่วงความยาวต่าง ๆ เช่นส่วนหัว
Matthew

8
คำตอบที่ดี; หนึ่งเคล็ดลับ: การเว้นวรรคอยู่ใน px (ดังนั้นคุณสามารถแปลง dp เป็น px ได้โดยใช้ Math.round (someDpValue * getResources (). getDisplayMetrics (). ความหนาแน่น))
Kevin Lee

1
มันใช้งานได้ดี แต่ฉันมีปัญหาฉันกำลังใช้ GridLayoutManager กับ spanCount 2 (ค่าเริ่มต้น) แต่ผู้ใช้สามารถเปลี่ยน spanCount ได้ดังนั้นเมื่อ spanCount เปลี่ยนจากตำแหน่งเริ่มต้นจะมีช่องว่างที่มองเห็นได้มากกว่าในบางตำแหน่งเช่นถ้า spanCount จะ 3 padding / margin ของ 2,3 8,9 12,13 เป็นต้น
Haris Qureshi

2
ใช้งานได้ดี! แต่ฉันมีปัญหากับ StaggeredGridLayoutManager imgur.com/XVutH5uระยะขอบแนวนอนบางครั้งก็แตกต่างกัน
Ufkoku

2
สิ่งนี้ไม่ทำงานเมื่อเลย์เอาต์เป็น rtl (สำหรับ 2 คอลัมน์ขึ้นไป) ปัจจุบันช่องว่างระหว่างคอลัมน์ไม่ถูกต้องเมื่ออยู่ในโหมด rtl คุณต้องแทนที่: outRect.left ด้วย outRect.right เมื่ออยู่ใน rtl
Masoud Mohammadi

83

ต่อไปนี้เป็นวิธีแก้ไขปัญหาอย่างง่ายแบบทีละขั้นตอนหากคุณต้องการเว้นระยะห่างเท่ากันรอบ ๆ รายการและขนาดรายการเท่ากัน

ItemOffsetDecoration

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);
    }
}

การดำเนินงาน

ในซอร์สโค้ดของคุณเพิ่ม ค่าออฟเซ็ตรายการItemOffsetDecorationของคุณRecyclerView.ควรมีขนาดครึ่งหนึ่งของค่าจริงที่คุณต้องการเพิ่มเป็นช่องว่างระหว่างรายการ

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

นอกจากนี้รายการชุดค่าชดเชยเป็นช่องว่างสำหรับด้านและระบุRecyclerViewandroid: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"/>

สมบูรณ์แบบเรียบง่ายและมีประสิทธิภาพ
B.shruti

28

ลองสิ่งนี้ มันจะดูแลระยะห่างที่เท่ากันรอบตัว ทำงานได้ทั้งกับ List, Grid และ StaggeredGrid

แก้ไข

รหัสที่อัปเดตควรจัดการกับเคสมุมเกือบทั้งหมดด้วยช่วงการวางแนว ฯลฯ โปรดทราบว่าหากใช้ setSpanSizeLookup () กับ GridLayoutManager ให้ตั้งค่า setSpanIndexCacheEnabled () เพื่อเหตุผลด้านประสิทธิภาพ

หมายเหตุดูเหมือนว่าด้วย StaggeredGrid ดูเหมือนว่าจะมีข้อผิดพลาดที่ดัชนีของเด็ก ๆ จะแปลกประหลาดและยากที่จะติดตามดังนั้นรหัสด้านล่างอาจทำงานได้ไม่ดีนักกับ 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);
  }
}

หวังว่ามันจะช่วย


1
ฉันมีระยะห่างสองเท่าหลังบรรทัดแรกของรายการ มันเกิดขึ้นเพราะ parent.getChildCount () ส่งคืน 1 สำหรับรายการแรก 2 สำหรับวินาทีและต่อไป ดังนั้นฉันขอแนะนำเพิ่มช่องว่างให้กับรายการของขอบบนเช่น: outRect.top = childIndex <spanCount? spacingInPixels: 0; และเพิ่มช่องว่างด้านล่างสำหรับแต่ละรายการ: outRect.bottom = spacingInPixels;
IvanP

ในช่วงเวลาของการเลื่อน RecyclerView ระยะห่างเปลี่ยนไป
Yugesh

3
ฉันคิดว่า parent.getChildCount () ควรเปลี่ยนเป็น "parent.getLayoutManager (). getItemCount ()" นอกจากนี้ฟังก์ชัน isBottomEdge จำเป็นต้องเปลี่ยนเป็น "return childIndex> = childCount - spanCount + spanIndex" หลังจากเปลี่ยนสิ่งเหล่านี้ฉันได้ระยะห่างเท่ากัน แต่โปรดทราบว่าวิธีการแก้ปัญหานี้ไม่ได้ให้ขนาดรายการที่เท่ากันถ้าการนับ span มากกว่า 2 เนื่องจากค่าออฟเซ็ตแตกต่างกันไปขึ้นอยู่กับตำแหน่ง
yqritc

1
@yqritc ขอบคุณสำหรับ nocticing parent.getChildCount () ฉันได้อัปเดตคำตอบของฉันเพื่อใช้ parent.getLayoutManager (). getItemCount ()
Pirdad Sakhizada

2
มันใช้งานได้ดีมากนอกกรอบแม้จะมีช่วงความแปรปรวนขอแสดงความยินดีและขอขอบคุณ!
Pierre-Luc Paour

21

รหัสต่อไปนี้จะจัดการกับ StaggeredGridLayoutManager, GridLayoutManager และ 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;
    }
}

จากนั้นใช้มัน

mRecyclerView.addItemDecoration(new SpacesItemDecoration(mMargin));

1
นี่คือหนึ่งที่ง่ายที่สุด สิ่งสำคัญอย่างหนึ่งคือคุณต้องเพิ่มการเติมไปยังพาเรนต์ใน xml ด้วย ในกรณีของฉันมันทำงานอย่างนั้น ขอบคุณ
กลั้ว

การSpaceItemDecorationเพิ่มช่องว่างให้กับพาเรนต์จริง (มุมมองรีไซเคิล)
Mark Hetherington

เพียงhalfSpacepadding ปรากฏ (ไปทางด้านขวา) เมื่อฉันยังไม่ได้ตั้งช่องว่างภายในไปยังผู้ปกครองใน XML
Samir

มันหายไปทางด้านขวาเท่านั้นเหรอ? อาจเป็นได้ว่าคุณมีพื้นที่ว่างครึ่งหนึ่งตั้งค่าเป็น LeftPadding ทางด้านซ้ายแล้วใน xml และรหัสนี้จะตรวจสอบว่ามีการตั้งค่าช่องว่างด้านซ้ายบน RecyclerView หรือไม่
Mark Hetherington

ฉันไม่มีชุด padding ใด ๆ ใน xml
Samir

11

นี่คือโซลูชันที่ไม่ต้องการ "spanCount" (จำนวนคอลัมน์) ฉันใช้เพราะฉันใช้GridAutofitLayoutManager (คำนวณจำนวนคอลัมน์ตามขนาดเซลล์ที่ต้องการ)

(ระวังว่าสิ่งนี้จะใช้ได้กับ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
                }
            }

        }

    }
}

นี่คือGridAutofitLayoutManagerคือทุกคนที่สนใจ:

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);
    }
}

สุดท้าย:

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

สวัสดี มันใช้งานได้ดี แต่ฉันใช้หัวข้อกับโซลูชันของคุณ คุณช่วยแนะนำให้บรรลุส่วนหัวแบบเต็มความกว้างได้อย่างไร
Ajeet

กรุณาคุณสามารถตรวจสอบตำแหน่งที่มีผู้จัดการรูปแบบดังต่อไปนี้layoutManager.getPosition(view)หลังจากตรวจสอบว่าตำแหน่งเป็นศูนย์ที่จะเป็นส่วนหัวของคุณ .. ด้วยวิธีนี้จะช่วยให้คุณสามารถเพิ่มส่วนหัวที่ตำแหน่งใด ๆ ที่คุณต้องการ :)
Mina Samir

9

มีวิธีแก้ปัญหาเพียงวิธีเดียวเท่านั้นที่คุณสามารถจดจำและนำไปใช้ได้ทุกที่ที่ต้องการ ไม่มีข้อบกพร่องไม่มีการคำนวณที่บ้า ใส่ระยะขอบให้กับเลย์เอาต์ของการ์ด / ไอเท็มและวางขนาดเดียวกันกับช่องใส่ใน 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"/>

UPDATE: ป้อนคำอธิบายรูปภาพที่นี่


มันใช้งานได้ดี! คุณช่วยอธิบายเรื่องนี้ได้ไหม
elyar abad

ขอบคุณมาก! ฉันกำลังมองหาเหตุผลทางเทคนิคว่าทำไมความร่วมมือดังกล่าวระหว่างการเติมเต็มของผู้รีไซเคิลและการกำหนดระยะขอบของรายการเป็นสิ่งจำเป็น ไม่ว่าคุณจะทำอะไรมากสำหรับฉัน . .
elyar abad

7

หากคุณต้องการแก้ไขขนาดของRecyclerViewรายการของคุณในทุกอุปกรณ์ คุณสามารถทำเช่นนี้

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>

กิจกรรม

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

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่


มันจะทำงานได้ตามขนาดหน้าจอหมายความว่ามันจะแสดงบนหน้าจอขนาด 5 นิ้วพวกเขามีลักษณะเหมือนกันกับขนาดหน้าจออื่น ๆ ด้วยหรือไม่
นิล

ขนาดของรายการจะได้รับการแก้ไข แต่ช่องว่างระหว่างรายการอาจแตกต่างกันคุณสามารถดูภาพ 2 ภาพด้านบนได้เพื่อให้เข้าใจ
Phan Van Linh

พวกเขาดูแตกต่างกันไปตามขนาดหน้าจอที่แตกต่างกัน แต่ก็ใช้งานได้ขอบคุณ
Sunil

6

คำตอบที่เลือกนั้นเกือบจะสมบูรณ์แบบ แต่ความกว้างของรายการอาจไม่เท่ากัน (ในกรณีของฉันมันสำคัญมาก) ดังนั้นฉันจึงลงเอยด้วยรหัสนี้ซึ่งเพิ่มพื้นที่นิดหน่อยดังนั้นไอเท็มต่างก็มีความกว้างเท่ากัน

   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
            }
        }
    }

}

ฉันจะเพิ่มบรรทัดต่อไปนี้ถ้ามีคนอย่างฉันใช้ GridLayoutManager with spanCount = 1 columnCount == 1 -> { outRect.left = space outRect.right = space }
hugemadness

5

คัดลอก @edwardaa ให้รหัสและฉันทำให้มันสมบูรณ์แบบเพื่อสนับสนุน 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;
        }
    }
}

ทุกคนสามารถคัดลอกรหัสจากgist.github.com/xingstarx/f2525ef32b04a5e67fecc5c0b5c4b939
Xingxing

4

คำตอบข้างต้นมีวิธีที่ชัดเจนในการตั้งค่าการจัดการระยะขอบของ GridLayoutManager และ LinearLayoutManager

แต่สำหรับ StaggeredGridLayoutManager คำตอบของ Pirdad Sakhizada บอกว่า: "มันอาจทำงานได้ไม่ดีกับ StaggeredGridLayoutManager" มันควรจะเป็นปัญหาเกี่ยวกับ IndexOfSpan

คุณสามารถรับมันด้วยวิธีนี้:

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
            }
        }
    }
}

แตกต่างเล็กน้อยจากคำตอบของ edwardaa ความแตกต่างคือวิธีการกำหนดคอลัมน์เนื่องจากในกรณีเช่นรายการที่มีความสูงต่าง ๆ คอลัมน์จะไม่สามารถกำหนดได้โดยเพียง% 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

นี่คือการปรับเปลี่ยนของฉันSpacesItemDecorationซึ่งอาจใช้เวลาnumOfColumsและพื้นที่อย่างเท่าเทียมกันด้านบนด้านล่างด้านซ้ายและขวา

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;
        }*/
    }
}

และใช้โค้ดด้านล่างในตรรกะของคุณ

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

2

มีวิธีแก้ปัญหาที่ง่ายและยืดหยุ่นมากสำหรับปัญหานี้โดยใช้ XML เท่านั้นซึ่งทำงานได้กับทุก LayoutManager

สมมติว่าคุณต้องการเว้นวรรคเท่ากับ X (8dp เป็นต้น)

  1. ล้อมรายการ CardView ของคุณในเค้าโครงอื่น

  2. กำหนดให้เค้าโครงด้านนอกมีช่องว่างภายใน X / 2 (4dp)

  3. ทำให้พื้นหลังเค้าโครงด้านนอกโปร่งใส

...

<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. ให้ Recycler ของคุณดูการเติม X / 2 (4dp)

...

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

และนั่นมัน คุณมีระยะห่างที่สมบูรณ์แบบของ X (8dp)


2

สำหรับผู้ที่มีปัญหากับ staggeredLayoutManager (เช่นhttps://imgur.com/XVutH5u )

วิธีการของ recyclerView:

getChildAdapterPosition(view)
getChildLayoutPosition(view)

บางครั้งส่งคืน -1 เป็นดัชนีดังนั้นเราอาจประสบปัญหาในการตั้งค่า itemDecor โซลูชันของฉันคือแทนที่วิธีของ ItemDecoration ที่เลิกใช้แล้ว:

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

แทนมือใหม่:

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

แบบนี้:

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
                    ...
            }
        });

ดูเหมือนว่าจะทำงานให้ฉันจนถึงตอนนี้ :)


สุดยอดคำตอบชาย! ใช้งานได้กับทุกกรณีรวมถึง GridLayoutManager "ปกติ" ที่ไม่สมมาตรซึ่งคุณมีรายการส่วนหัวระหว่างรายการ ขอบคุณ!
Shirane85

2

คำตอบสำหรับคำถามนี้ดูซับซ้อนกว่าที่ควรจะเป็น นี่คือสิ่งที่ฉันทำ

สมมติว่าคุณต้องการเว้นวรรค 1dp ระหว่างรายการกริด ทำดังต่อไปนี้:

  1. เพิ่มการเติม0.5dpไปที่แต่ละรายการ
  2. เพิ่มช่องว่างภายใน -0.5dpไปที่ RecycleView
  3. แค่นั้นแหละ! :)

1

สิ่งนี้จะทำงานRecyclerViewกับส่วนหัวเช่นกัน

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;
        }
    }
    }
}

headerNum คืออะไร
Tim Kranen

1

คำตอบของ yqritc ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน ฉันใช้ Kotlin แต่นี่ก็เทียบเท่ากัน

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)
    }
}

ทุกอย่างอื่นเหมือนกัน


1

สำหรับผู้ใช้StaggeredGridLayoutManagerโปรดระวังคำตอบมากมายที่นี่รวมถึงผู้ที่ได้รับการโหวตมากที่สุดจะคำนวณคอลัมน์รายการด้วยรหัสด้านล่าง:

int column = position % spanCount

ซึ่งสันนิษฐานว่ารายการที่ 1/3/5 / .. จะอยู่ทางด้านซ้ายและรายการที่ 2/4/6 / .. มักจะอยู่ทางด้านขวา สมมติฐานนี้เป็นจริงเสมอ เลขที่

สมมติว่ารายการที่ 1 ของคุณสูง 100dp และที่สองคือเพียง 50dp เดาว่ารายการที่ 3 ของคุณอยู่ทางซ้ายหรือขวาที่ไหน


0

ฉันลงเอยด้วยการทำเช่นนั้นสำหรับRecyclerViewของฉันด้วย GridLayoutManager และ HeaderViewHeaderView

ในรหัสด้านล่างฉันตั้งช่องว่าง 4dp ระหว่างทุกรายการ (2dp รอบ ๆ ทุกรายการและช่องว่างภายใน 2dp รอบ 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" />

ชิ้นส่วน / กิจกรรม

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

SpaceItemDecoration.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

ในการทำhttps://stackoverflow.com/a/29905000/1649371 (ด้านบน) โซลูชันทำงานฉันต้องแก้ไขวิธีต่อไปนี้ (และการโทรที่ตามมาทั้งหมด)

@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

หากคุณมีสวิตช์สลับที่สลับระหว่างรายการเป็นตารางอย่าลืมโทรrecyclerView.removeItemDecoration()ก่อนตั้งค่าการตกแต่งรายการใหม่ ถ้าไม่เช่นนั้นการคำนวณใหม่สำหรับระยะห่างจะไม่ถูกต้อง


บางสิ่งเช่นนี้

        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

หากคุณกำลังใช้HeaderกับGridLayoutManager ให้ใช้โค้ดนี้เขียนเป็นkotlinเพื่อเว้นช่องว่างระหว่างกริด:

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
            }
        }
    }
    }

และผ่านItemDecorationไปrecyclerviewเป็น

mIssueGridView.addItemDecoration(SpacesItemDecoration(10))

0

เมื่อใช้ปัญหา CardView สำหรับเด็กที่มีช่องว่างระหว่างรายการสามารถแก้ไขได้โดยการตั้งค่าแอพ: cardUseCompatPadding เป็นจริง

สำหรับระยะขอบที่ใหญ่ขึ้นให้ขยายระดับความสูงของรายการ CardElevation เป็นทางเลือก (ใช้ค่าเริ่มต้น)

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

-1

ขอบคุณคำตอบของ edwardaa https://stackoverflow.com/a/30701422/2227031

อีกประเด็นที่ควรทราบคือ:

ถ้าระยะห่างรวมและรายการทั้งหมดกว้างไม่เท่ากับความกว้างของหน้าจอคุณต้องปรับ itemWidth เช่นบนอะแด็ปเตอร์บนวิธีการ BindViewHolder

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

รุ่น Kotlin ฉันทำตามคำตอบที่ดีโดย 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
  }

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.