วิธีเพิ่มตัวคั่นและช่องว่างระหว่างรายการใน RecyclerView


938

นี่คือตัวอย่างของวิธีที่สามารถทำได้ก่อนหน้านี้ในListViewชั้นเรียนโดยใช้พารามิเตอร์ตัวแบ่งและdividerHeight :

<ListView
    android:id="@+id/activity_home_list_view"
    android:layout_width="match_parent" 
    android:layout_height="match_parent"
    android:divider="@android:color/transparent"
    android:dividerHeight="8dp"/>

อย่างไรก็ตามฉันไม่เห็นความเป็นไปได้ดังกล่าวในRecyclerViewชั้นเรียน

<android.support.v7.widget.RecyclerView
    android:id="@+id/activity_home_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical"/>

ในกรณีนี้การกำหนดระยะขอบและ / หรือเพิ่มมุมมองตัวแบ่งที่กำหนดเองลงในเลย์เอาต์ของรายการหรือไม่ก็เป็นวิธีที่ดีกว่าเพื่อให้บรรลุเป้าหมายของฉันหรือไม่


สิ่งนี้ช่วยฉันได้: stackoverflow.com/questions/26892296/…
Jared Burrows

@EyesClear เพิ่มรายการ <TextView /> อีก XML และใช้ในรายการกิจกรรมเดียวกัน
Amitsharma

7
มีคลาสในการสนับสนุน lib com.homeretailgroup.argos.android.view.decorators.DividerItemDecorationและใช้งานดังนี้:mRecyclerView.addItemDecoration(new DividerItemDecoration(activity, LinearLayoutManager.VERTICAL));
fada21

คุณสามารถเพิ่มระยะขอบด้านล่างลงในรายการของคุณสำหรับรายการแนวตั้งและมันสามารถใช้เป็นตัวแบ่งได้หรือไม่
resw67

วิธีที่ง่ายที่สุดคือการเพิ่มระยะขอบบน / ล่างรอบรายการแรกในแถวของอะแดปเตอร์ หุ่นยนต์: layout_marginBottom = "4DP" (หมายเหตุการเพิ่มอัตรากำไรขั้นต้นในรูปแบบที่ผู้ปกครองจะไม่ตัดมัน.)
pstorli

คำตอบ:


1227

อัปเดตเดือนตุลาคม 2559

ไลบรารีการสนับสนุน Android เวอร์ชัน 25.0.0 เวอร์ชันที่แนะนำDividerItemDecoration:

DividerItemDecoration เป็น RecyclerView.ItemDecoration LinearLayoutManagerที่สามารถนำมาใช้เป็นตัวแบ่งระหว่างรายการของที่ สนับสนุนทั้งสองHORIZONTALและVERTICALทิศทาง

การใช้งาน:

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
    layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);

คำตอบก่อนหน้า

บางคำตอบอาจใช้วิธีการที่เลิกใช้มาแล้วหรือไม่ได้ให้วิธีแก้ปัญหาที่สมบูรณ์ดังนั้นฉันจึงพยายามสรุปสรุปสั้น ๆ


ซึ่งแตกต่างจากListViewที่RecyclerViewชั้นไม่มีพารามิเตอร์ divider ที่เกี่ยวข้อง แต่คุณจำเป็นต้องขยายItemDecorationเป็นRecyclerViewระดับชั้น 's:

ItemDecorationช่วยให้โปรแกรมประยุกต์เพื่อเพิ่มพิเศษถอนเงินและรูปแบบการชดเชยมุมมองรายการจากข้อมูลชุดอะแดปเตอร์ สิ่งนี้มีประโยชน์สำหรับการวาดตัวคั่นระหว่างไอเท็มไฮไลต์ขอบเขตการจัดกลุ่มภาพและอื่น ๆ

ทั้งหมดItemDecorationsจะมีการวาดเพื่อที่พวกเขาถูกเพิ่มก่อนที่มุมมองรายการ (ในonDraw()) และหลังจากที่รายการ (ใน onDrawOver ( Canvas, ,RecyclerViewRecyclerView.State)

Vertical การเว้นวรรค ItemDecoration

ขยายItemDecorationเพิ่มตัวสร้างที่กำหนดเองซึ่งใช้พื้นที่heightเป็นพารามิเตอร์และgetItemOffsets()วิธีการแทนที่:

public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {

    private final int verticalSpaceHeight;

    public VerticalSpaceItemDecoration(int verticalSpaceHeight) {
        this.verticalSpaceHeight = verticalSpaceHeight;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
            RecyclerView.State state) {
        outRect.bottom = verticalSpaceHeight;
    }
}

หากคุณไม่ต้องการแทรกช่องว่างด้านล่างของรายการสุดท้ายให้เพิ่มเงื่อนไขต่อไปนี้:

if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
            outRect.bottom = verticalSpaceHeight;
}

หมายเหตุ: คุณยังสามารถปรับเปลี่ยนoutRect.top, outRect.leftและoutRect.rightคุณสมบัติสำหรับผลที่ต้องการ

divider ItemDecoration

วิธีการขยายItemDecorationและแทนที่onDraw():

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};

    private Drawable divider;

    /**
     * Default divider will be used
     */
    public DividerItemDecoration(Context context) {
        final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
        divider = styledAttributes.getDrawable(0);
        styledAttributes.recycle();
    }

    /**
     * Custom divider will be used
     */
    public DividerItemDecoration(Context context, int resId) {
        divider = ContextCompat.getDrawable(context, resId);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + divider.getIntrinsicHeight();

            divider.setBounds(left, top, right, bottom);
            divider.draw(c);
        }
    }
}

คุณสามารถเรียก constructor แรกที่ใช้ Android divider attribute เริ่มต้นหรืออันที่สองที่ใช้ drawable ของคุณเองเช่น drawable / divider.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <size android:height="1dp" />
    <solid android:color="#ff992900" />
</shape>

หมายเหตุ: หากคุณต้องการให้ตัวคั่นถูกวาดทับรายการของคุณให้แทนที่onDrawOver()เมธอดแทน

การใช้

หากต้องการใช้เพิ่มระดับใหม่ของคุณVerticalSpaceItemDecorationหรือDividerSpaceItemDecorationจะRecyclerViewยกตัวอย่างเช่นในส่วนของonCreateView()วิธีการ:

private static final int VERTICAL_ITEM_SPACE = 48;
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_feed, container, false);

    recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_home_recycler_view);
    linearLayoutManager = new LinearLayoutManager(getActivity());
    recyclerView.setLayoutManager(linearLayoutManager);

    //add ItemDecoration
    recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(VERTICAL_ITEM_SPACE));
    //or
    recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));
    //or
    recyclerView.addItemDecoration(
            new DividerItemDecoration(getActivity(), R.drawable.divider));

    recyclerView.setAdapter(...);

    return rootView;
}

นอกจากนี้ยังมีห้องสมุดของ Lucas Rochaซึ่งควรจะทำให้กระบวนการตกแต่งรายการง่ายขึ้น ยังไม่ได้ลองเลย

ระหว่างคุณสมบัติของมันคือ:

  • คอลเลกชันของตกแต่งรายการสินค้ารวมถึง:
  • ระยะห่างรายการวงเวียนแนวนอน / แนวตั้ง
  • รายการสินค้า

3
@droppin_science ฉันถูกต้องหากฉันผิด แต่ฉันไม่ได้สร้างวัตถุใด onDraw()ๆ ฉันแค่อ้างอิงอินสแตนซ์ที่มีอยู่แล้ว
EyesClear

1
ฉันสงสัยว่าควรใช้ 'ระบายสี' แทนการสร้าง drawable หรือไม่ แล้วฉันจะโทรcanvas.drawLine(startX, startY, stopX, stopY, mPaint)เข้าไปได้onDrawOverไหม? มีความแตกต่างด้านประสิทธิภาพหรือไม่
Arst

1
เพียงแค่ความคิดเห็นที่ให้ข้อมูล: เพิ่มช่องว่างในรายการสุดท้ายเสมอหากคุณวางแผนที่จะเพิ่มรายการในรายการของคุณในภายหลัง หากคุณไม่ทำอย่างนั้นเมื่อเพิ่มรายการมันจะไม่มีที่ว่าง ขอบคุณสำหรับ VerticalSpace!
Tsuharesu

24
DividerItemDecoration ดังที่แสดงไว้ด้านบนจะไม่ทำงานหากรายการนั้นทึบอย่างสมบูรณ์ตัวหารจะได้รับการถอนออกจากรายการ ในกรณีนั้นคุณต้องแทนที่ getItemOffsets () ด้วยและเพิ่ม offset ด้านล่างลงใน outRect เพื่อให้ตัวแบ่งสิ้นสุดลงนอกรายการ หรือคุณสามารถแทนที่ onDrawOver () แทน onDraw () เพื่อวาดตัวแบ่งที่อยู่ถัดจากรายการ
jpop

115
หน้าทั้งหมดของรหัสเพื่อเพิ่มตัวแบ่งเพื่อ recyclerView เป็นคำตอบที่ดีที่สุด อัปยศคุณ google
ระวัง 7j

480

เพียงเพิ่ม

recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
                DividerItemDecoration.VERTICAL));

นอกจากนี้คุณอาจต้องเพิ่มการพึ่งพา
compile 'com.android.support:recyclerview-v7:27.1.0'

แก้ไข:

สำหรับการปรับแต่งเล็กน้อยคุณสามารถเพิ่ม drawable ที่กำหนดเองได้:

DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
itemDecorator.setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.divider));

คุณมีอิสระที่จะใช้ drawable ที่กำหนดเองได้เช่น:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <solid android:color="@color/colorPrimary"/>
    <size android:height="0.5dp"/>
</shape>

กิจกรรมไม่จำเป็น บริบทเพียงพอแล้ว
mac229

นี่จะต้องเป็นคำตอบที่ถูกต้อง โปรดเปลี่ยน getActivity เป็นเพียงบริบท
Jhon Fredy Trujillo Ortega

นอกจากนี้ยังเป็นการดีกว่าที่จะได้รับการวางแนวจาก LayoutManager ของคุณ
lsrom

ขอบคุณ! นอกจากนี้คุณยังสามารถใช้Configurationสำหรับตัวแบ่งแนวตั้ง:if (orientation == Configuration.ORIENTATION_LANDSCAPE) { recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL)); } else { recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));}
46419

3
คำตอบที่ดี แต่มันก็เพิ่มตัวแบ่งหลังจากรายการสุดท้าย
CoolMind

256

ฉันขอนำความสนใจของคุณไปยังไฟล์นี้ใน Github โดย Alex Fu: https://gist.github.com/alexfu/0f464fc3742f134ccd1e

เป็นไฟล์ตัวอย่าง DividerItemDecoration.java "ดึงโดยตรงจากการสนับสนุน" ( https://plus.google.com/103498612790395592106/posts/VVEB3m7NkSS )

ฉันสามารถรับเส้นแบ่งอย่างดีหลังจากนำเข้าไฟล์นี้ในโครงการของฉันและเพิ่มเป็นรายการตกแต่งในมุมมองของนักรีไซเคิล

นี่คือลักษณะที่ onCreateView ของฉันมีลักษณะเหมือนในส่วนของฉันที่มี Recyclerview:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_recycler_view, container, false);

    mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
    mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));

    mRecyclerView.setHasFixedSize(true);
    mLayoutManager = new LinearLayoutManager(getActivity());
    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());

    return rootView;
}

ฉันแน่ใจว่าสามารถใส่สไตล์เพิ่มเติมได้ แต่มันเป็นจุดเริ่มต้น :)


คุณจะเพิ่มวิธีแทนที่: "footerDividersEnabled", "headerDividersEnabled", "listSelector", "fastScrollEnabled", "smoothScrollbar", "textFilterEnabled"?
นักพัฒนา android

อินพุตใด ๆ บนวิธีการใส่สไตล์?
nizam.sp

เพื่อจัดรูปแบบโซลูชันนี้คุณต้องแทนที่แอตทริบิวต์ "android: listDivider" ในชุดรูปแบบของคุณ
Pavel Dudka

1
ตัวแบ่งไม่ทำงานกับ RecyclerView คุณต้องใช้ RecyclerView.itemDecoration ดูคำตอบนี้: stackoverflow.com/a/27664023/2311451
Cocorico

3
เหตุใดตัวแบ่งจึงขยายความกว้างทั้งหมดของรายการ วิธีการแสดงเช่นในgoogle.co.th/design/spec/components/lists.html#lists-specs
ชิป

156

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.getChildAdapterPosition(view) == 0) {
            outRect.top = space;
        }
    }
}

ฉันได้รับพื้นที่ แต่ฉันจะแบ่งได้อย่างไร
Pankaj Nimgade

26
getChildPositionเลิกใช้แล้วgetChildAdapterPositionสามารถใช้แทนได้
EyesClear

4
อย่าลืม (เหมือนที่ฉันทำ) เพื่อลบการโทรsuper.getItemOffsetsมิฉะนั้นการชดเชยของคุณจะถูกเขียนทับ
jayeffkay

@EyesClear ไม่ควรgetChildLayoutPositionใช้หรือไม่
Avinash R

3
สิ่งนี้ใช้ระยะห่างเป็นพิกเซลหรือไม่
filthy_wizard

108

สิ่งที่ง่ายคือการตั้งค่าสีพื้นหลังสำหรับRecyclerViewและสีพื้นหลังที่แตกต่างกันสำหรับรายการ นี่คือตัวอย่าง ...

<android.support.v7.widget.RecyclerView
    android:background="#ECEFF1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:scrollbars="vertical"/>

และรายการTextView (สามารถเป็นอะไรก็ได้) โดยมีระยะขอบด้านล่าง "x" dp หรือ px

<TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="1dp"
    android:background="#FFFFFF"/>

ผลลัพธ์ ...

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


2
ช่างเป็นกลอุบาย! ต้องการเพียงแค่ทำให้รายการเป็นสีขาวขณะที่โหลด
Hamzeh Soboh

36
ระวังการถอนเงินมากเกินไป!
shem

@shem คุณสามารถทำอย่างละเอียด?
RominaV

7
เมื่อวาดในเลเยอร์ Android สองเลเยอร์หนึ่งอยู่เหนืออีกอันหนึ่ง (พื้นหลังกิจกรรมพื้นหลังมุมมองรีไซเคิลและพื้นหลังมุมมองรายการ) - Android วาดพวกเขาทั้งหมดรวมถึงสิ่งที่ผู้ใช้มองไม่เห็น ที่เรียกว่าการวาดทับและอาจส่งผลกระทบต่อประสิทธิภาพการทำงานของคุณเพิ่มเติมได้ที่นี่: youtube.com/watch?v=T52v50r-JfE
เชม

41

ฉันคิดว่าการใช้ตัวแบ่งเรียบง่ายจะช่วยคุณ

ในการเพิ่มตัวคั่นในแต่ละรายการ:
1- เพิ่มลงในไดเรคทอรี drawable line_divider.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
    android:width="1dp"
    android:height="1dp" />
<solid android:color="#999999" />
</shape>

2- สร้างคลาส SimpleDividerItemDecoration
ฉันใช้ตัวอย่างนี้เพื่อกำหนดคลาสนี้:
https://gist.github.com/polbins/e37206fbc444207c0e92

package com.example.myapp;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.example.myapp.R;

public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration{
private Drawable mDivider;

public SimpleDividerItemDecoration(Resources resources) {
    mDivider = resources.getDrawable(R.drawable.line_divider);
}

public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    int left = parent.getPaddingLeft();
    int right = parent.getWidth() - parent.getPaddingRight();

    int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View child = parent.getChildAt(i);

        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

        int top = child.getBottom() + params.bottomMargin;
        int bottom = top + mDivider.getIntrinsicHeight();

        mDivider.setBounds(left, top, right, bottom);
        mDivider.draw(c);
    }
  }
}


3- ในกิจกรรมหรือส่วนที่ใช้ RecyclerView ด้านใน onCreateView เพิ่มสิ่งนี้:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
 RecyclerView myRecyclerView = (RecyclerView) layout.findViewById(R.id.my_recycler_view);
 myRecyclerView.addItemDecoration(new SimpleDividerItemDecoration(getResources()));
 ....
 }


4- ในการเพิ่มระยะห่างระหว่างรายการ
คุณเพียงแค่ต้องเพิ่มคุณสมบัติการขยายไปยังมุมมองรายการของคุณ

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:padding="4dp"
>
..... item structure
</RelativeLayout>

ฉันจะทำให้มันทำงานกับ GridLayoutManager ได้อย่างไรเพื่อแสดงตัวแบ่งแนวตั้งระหว่างเซลล์ด้วย?
นักพัฒนา android

2
resources.getDrawable () เลิกใช้แล้วในขณะนี้ คุณสามารถผ่านในบริบทและใช้ ContextCompat.getDrawable (บริบท, R.drawable.line_divider)
Eric B.

36

ItemAnimatorsในฐานะที่เราได้ตั้งไว้ ItemDecoratorไม่เข้าหรือออกพร้อมกับการเคลื่อนไหว

ฉันเพียงแค่ลงเอยด้วยการมีบรรทัดดูในไฟล์เลย์เอาต์มุมมองรายการของแต่ละรายการ มันแก้ไขกรณีของฉัน DividerItemDecorationรู้สึกว่ามีเวทมนตร์มากเกินไปสำหรับตัวแบ่งที่เรียบง่าย

<View
    android:layout_width="match_parent"
    android:layout_height="1px"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:background="@color/lt_gray"/>

คุณพูดถูก ภาพเคลื่อนไหวไม่ทำงานกับ ItemDecoration ฉันไม่แน่ใจว่าทำไม แต่ไม่มีฉันระบุอะไรฉันได้รับภาพเคลื่อนไหวและฉันพบว่ามันน่ารำคาญมากและน่าเกลียดที่บรรทัดที่สร้างโดย ItemDecoration ไม่ปฏิบัติตาม ดังนั้นฉันจะใช้วิธีแก้ปัญหาเช่นคุณ
มิเชล

คุณจัดการกับรายการสุดท้ายอย่างไร
oldergod

@oldergod คุณชี้ไปที่จุดปวดที่ถูกต้อง ก่อนอื่นฉันจะเห็นด้วยกับการออกแบบที่มีตัวแบ่งในรายการสุดท้ายเช่นกัน แต่ถ้าคุณไม่ต้องการ กำหนดรหัสให้กับมุมมองนี้และซ่อนใน bindView หากตำแหน่งสุดท้าย
Javanator

@ Javanator ฉันเห็นด้วยวิธีเดียวกับที่ฉันใช้ ขอบคุณ
oldergod

ที่ง่ายที่สุดคือดีที่สุด
hyyou2010

27

ง่ายมากคุณไม่จำเป็นต้องใช้รหัสที่ซับซ้อน

DividerItemDecoration divider = new 
DividerItemDecoration(mRVMovieReview.getContext(), 
DividerItemDecoration.VERTICAL);
divider.setDrawable(
    ContextCompat.getDrawable(getBaseContext(), R.drawable.line_divider)
);
mRVMovieReview.addItemDecoration(divider);

เพิ่มใน drawable ของคุณ: line_divider.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
  android:shape="rectangle">
    <size android:height="1dp" />
    <solid android:color="@android:color/black" />
</shape>

21

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

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/dividerColor"/>

DividerItemDecoration หยุดทำงานหลังจากที่ฉันมีข้อมูลระดับความสูงของการออกแบบวัสดุ (เพื่อให้ได้ผลเช่นเดียวกับในกล่องจดหมาย); มันซับซ้อนเกินไปสำหรับสิ่งที่ง่าย วิธีนี้ง่ายและใช้งานได้
DenisGL

21

วิธีที่ฉันจัดการมุมมอง Divider และ Divider Insets คือการเพิ่มส่วนขยาย RecyclerView

1

เพิ่มไฟล์นามสกุลใหม่โดยตั้งชื่อดูหรือ RecyclerView:

RecyclerViewExtension.kt

และเพิ่มsetDividerเมธอดส่วนขยายภายในไฟล์ RecyclerViewExtension.kt

/*
* RecyclerViewExtension.kt
* */
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView


fun RecyclerView.setDivider(@DrawableRes drawableRes: Int) {
    val divider = DividerItemDecoration(
        this.context,
        DividerItemDecoration.VERTICAL
    )
    val drawable = ContextCompat.getDrawable(
        this.context,
        drawableRes
    )
    drawable?.let {
        divider.setDrawable(it)
        addItemDecoration(divider)
    }
}

2

สร้างไฟล์ทรัพยากร Drawable ภายในdrawableแพ็คเกจเช่นrecycler_view_divider.xml:

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetLeft="10dp"
    android:insetRight="10dp">

    <shape>
        <size android:height="0.5dp" />
        <solid android:color="@android:color/darker_gray" />
    </shape>

</inset>

ซึ่งคุณสามารถระบุซ้ายและขวาขอบบนและandroid:insetLeftandroid:insetRight

3

ในกิจกรรมหรือชิ้นส่วนที่ RecyclerView เริ่มต้นคุณสามารถตั้งค่า drawable แบบกำหนดเองได้โดยการโทร:

recyclerView.setDivider(R.drawable.recycler_view_divider)

4

ไชโย🍺

แถว RecyclerView พร้อมตัวแบ่ง


16

หากใครก็ตามที่ต้องการเพิ่มเพียงพูดระยะห่าง 10dp ระหว่างรายการคุณสามารถทำได้โดยตั้งค่า drawable เป็นDividerItemDecoration:

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
    recyclerView.getContext(),
    layoutManager.getOrientation()
);

dividerItemDecoration.setDrawable(
    ContextCompat.getDrawable(getContext(), R.drawable.divider_10dp)
); 

divider_10dpแหล่งข้อมูล drawable มีอยู่ที่ไหน:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <size android:height="10dp"/>
    <solid android:color="@android:color/transparent"/>
</shape>


11

สิ่งนี้ไม่ได้แก้ปัญหา แต่เป็นวิธีแก้ปัญหาชั่วคราวคุณสามารถตั้งคุณสมบัติuseCompatPaddingบนการ์ดในโครงร่าง XML ของคุณเพื่อให้สามารถวัดได้เช่นเดียวกับในเวอร์ชันก่อนอมยิ้ม

card_view:cardUseCompatPadding="true"


11

สำหรับผู้ที่กำลังมองหาช่องว่างระหว่างรายการในRecyclerViewแนวทางของฉันที่คุณได้รับช่องว่างที่เท่ากันระหว่างรายการทั้งหมดยกเว้นในรายการแรกและรายการสุดท้ายที่ฉันให้ช่องว่างขนาดใหญ่กว่า ฉันเพียงใช้ padding ไปทางซ้าย / ขวาในแนวนอนLayoutManagerและบน / LayoutManagerล่างในแนวตั้ง

public class PaddingItemDecoration extends RecyclerView.ItemDecoration {

    private int mPaddingPx;
    private int mPaddingEdgesPx;

    public PaddingItemDecoration(Activity activity) {
        final Resources resources = activity.getResources();
        mPaddingPx = (int) resources.getDimension(R.dimen.paddingItemDecorationDefault);
        mPaddingEdgesPx = (int) resources.getDimension(R.dimen.paddingItemDecorationEdge);
    }

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

        final int itemPosition = parent.getChildAdapterPosition(view);
        if (itemPosition == RecyclerView.NO_POSITION) {
            return;
        }
        int orientation = getOrientation(parent);
        final int itemCount = state.getItemCount();

        int left = 0;
        int top = 0;
        int right = 0;
        int bottom = 0;

        /** HORIZONTAL */
        if (orientation == LinearLayoutManager.HORIZONTAL) {
            /** all positions */
            left = mPaddingPx;
            right = mPaddingPx;

            /** first position */
            if (itemPosition == 0) {
                left += mPaddingEdgesPx;
            }
            /** last position */
            else if (itemCount > 0 && itemPosition == itemCount - 1) {
                right += mPaddingEdgesPx;
            }
        }
        /** VERTICAL */
        else {
            /** all positions */
            top = mPaddingPx;
            bottom = mPaddingPx;

            /** first position */
            if (itemPosition == 0) {
                top += mPaddingEdgesPx;
            }
            /** last position */
            else if (itemCount > 0 && itemPosition == itemCount - 1) {
                bottom += mPaddingEdgesPx;
            }
        }

        if (!isReverseLayout(parent)) {
            outRect.set(left, top, right, bottom);
        } else {
            outRect.set(right, bottom, left, top);
        }
    }

    private boolean isReverseLayout(RecyclerView parent) {
        if (parent.getLayoutManager() instanceof LinearLayoutManager) {
            LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
            return layoutManager.getReverseLayout();
        } else {
            throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
        }
    }

    private int getOrientation(RecyclerView parent) {
        if (parent.getLayoutManager() instanceof LinearLayoutManager) {
            LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
            return layoutManager.getOrientation();
        } else {
            throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
        }
    }
}

dimens.xml

<resources>
    <dimen name="paddingItemDecorationDefault">10dp</dimen>
    <dimen name="paddingItemDecorationEdge">20dp</dimen>
</resources>

11

เพิ่มระยะขอบให้กับมุมมองของคุณมันใช้งานได้สำหรับฉัน

android:layout_marginTop="10dp"

หากคุณต้องการเพิ่มระยะห่างเท่ากันและต้องการทำในXMLเพียงตั้งค่าpaddingเป็นRecyclerViewจำนวนเท่ากันlayoutMarginกับรายการที่คุณขยายเข้าไปในของคุณRecyclerViewและปล่อยให้สีพื้นหลังเป็นตัวกำหนดสีของระยะห่าง


3
แม้ว่าสิ่งนี้จะได้ผล แต่นี่ไม่ใช่คำตอบที่ถูกต้องตัวอย่างเช่นเพราะสิ่งนี้ไม่ได้แก้ปัญหาโดยไม่ต้องทำอะไรเพิ่มเติมกับเลย์เอาต์แถวนอกจากนี้ที่ขอบ x1 จะปรากฏขึ้นที่ขอบด้านบนระหว่างขอบ x2 จะปรากฏขึ้น
Sreekanth Karumanaghat

นี่ไม่ใช่ความคิดที่ดีเพราะเอoverscrollฟเฟกต์เมื่อดึงที่ส่วนท้ายของรายการจะมีการเติมที่ไม่จำเป็นกับมันเมื่อใช้การRecyclerView
แพ็ด

เป็นการดีกว่าที่จะตัดเลย์เอาต์ของรายการใน Support Library CardView เพื่อให้คุณสามารถควบคุมคุณสมบัติอื่น ๆ เช่นระดับความสูง / เงา ฯลฯ : <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:id="@+id/card_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" card_view:cardElevation="4dp" <!-- your item's XML here --> </android.support.v7.widget.CardView>
kip2

11
  • นี่คือแฮ็คง่ายๆในการเพิ่มตัวแบ่ง
  • เพียงเพิ่มพื้นหลังให้กับเลย์เอาต์ของรายการรีไซเคิลของคุณดังนี้

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_border"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="5dp">
    
    <ImageView
        android:id="@+id/imageViewContactLogo"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginRight="10dp"
        android:src="@drawable/ic_user" />
    
    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.92"
        android:gravity="center|start"
        android:orientation="vertical">
    
    <TextView
        android:id="@+id/textViewContactName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    
    <TextView
        android:id="@+id/textViewStatusOrNumber"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:singleLine="true"
        android:text=""
        android:textAppearance="?android:attr/textAppearanceMedium" />
    </LinearLayout>
    
    <TextView
        android:id="@+id/textViewUnreadCount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:padding="5dp"
        android:text=""
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="@color/red"
        android:textSize="22sp" />
    
    <Button
        android:id="@+id/buttonInvite"
        android:layout_width="54dp"
        android:layout_height="wrap_content"
        android:background="@drawable/ic_add_friend" />
    </LinearLayout>

สร้าง shape_border.xml ต่อไปนี้ในโฟลเดอร์ drawable

  <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
      android:shape="rectangle" >
       <gradient
        android:angle="270"
        android:centerColor="@android:color/transparent"
        android:centerX="0.01"
        android:startColor="#000" />
    </shape>

นี่คือผลลัพธ์สุดท้าย - RecyclerView พร้อมตัวแบ่ง

นี่คือผลลัพธ์สุดท้าย - RecyclerView พร้อมตัวแบ่ง


1
นี่ไม่ใช่วิธีการที่แนะนำ แม้ว่า @EyesClear คำตอบบำเพ็ญ int ใน OnDraw และparent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1อาจจะparent.getChildAdapterPosition(view) > 0มีoutRect.bottom = mVerticalSpaceHeightการกลายเป็นoutRect.top = mVerticalSpaceHeightมันควรจะเป็นคำตอบที่ได้รับการยอมรับ
droppin_science

@droppin_science - คุณไม่สามารถละเลยได้โดยเพียงแค่บอกว่านี่ไม่ใช่วิธีการที่ต้องการมันให้ผลลัพธ์ที่แม่นยำตามที่คาดไว้ฉันยังดูคำตอบของ EyesClear แต่คำตอบนั้นซับซ้อนเกินไปสำหรับตัวหารแบบง่าย ๆ แต่ถ้าจำเป็นต้อง ทำการตกแต่งพิเศษด้วยไอเท็มจากนั้นอาจเป็นคำตอบที่ยอมรับได้
turbandroid

สำหรับผู้ลงคะแนนคำตอบนี้ได้รับในเวลาที่ไม่มีชั้นเรียนอย่างเป็นทางการสำหรับ DividerItemDecoration ดังนั้นเพียงเปรียบเทียบช่องว่างเวลาระหว่างคำตอบนี้กับคำตอบต่อไปนี้โดย Leo Droidcoder :)
turbandroid

9

ฉันแยก DividerItemDecoration จากแก่นสารที่เก่ากว่าและทำให้มันง่ายขึ้นเพื่อให้เหมาะกับกรณีการใช้งานของฉันและฉันยังปรับเปลี่ยนเพื่อวาดตัวหารตามที่วาดใน ListView รวมถึงตัวแบ่งหลังจากรายการสุดท้าย สิ่งนี้จะจัดการภาพเคลื่อนไหว ItemAnimator ในแนวตั้งด้วย:

1) เพิ่มคลาสนี้ในโครงการของคุณ:

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    private Drawable divider;

    public DividerItemDecoration(Context context) {
        try {
            final TypedArray a = context.obtainStyledAttributes(ATTRS);
            divider = a.getDrawable(0);
            a.recycle();
        } catch (Resources.NotFoundException e) {
            // TODO Log or handle as necessary.
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (divider == null) return;
        if (parent.getChildAdapterPosition(view) < 1) return;

        if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
            outRect.top = divider.getIntrinsicHeight();
        else
            throw new IllegalArgumentException("Only usable with vertical lists");
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (divider == null) {
            super.onDrawOver(c, parent, state);
            return;
        }

        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();
        final int childCount = parent.getChildCount();

        for (int i = 0; i < childCount; ++i) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int size = divider.getIntrinsicHeight();
            final int top = (int) (child.getTop() - params.topMargin - size + child.getTranslationY());
            final int bottom = top + size;
            divider.setBounds(left, top, right, bottom);
            divider.draw(c);

            if (i == childCount - 1) {
                final int newTop = (int) (child.getBottom() + params.bottomMargin + child.getTranslationY());
                final int newBottom = newTop + size;
                divider.setBounds(left, newTop, right, newBottom);
                divider.draw(c);
            }
        }
    }

    private int getOrientation(RecyclerView parent) {
        if (!(parent.getLayoutManager() instanceof LinearLayoutManager))
            throw new IllegalStateException("Layout manager must be an instance of LinearLayoutManager");
        return ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
    }
}

2) เพิ่มมัณฑนากรใน RecylerView ของคุณ:

recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));

ถูกต้องมันมีไว้สำหรับ LinearLayoutManager คุณสามารถนำแนวคิดเบื้องหลังมาปรับใช้กับ GridLayoutManager
เรียนรู้ OpenGL ES

8

แทนที่จะสร้างshape xmlสำหรับเปลี่ยนความสูงและสีของตัวหาร คุณสามารถสร้างเช่นโปรแกรม

val divider = DividerItemDecoration(context,
        DividerItemDecoration.VERTICAL)

divider.setDrawable(ShapeDrawable().apply {
    intrinsicHeight = resources.getDimensionPixelOffset(R.dimen.dp_15)
    paint.color = Color.RED // note: currently (support version 28.0.0), we can not use tranparent color here, if we use transparent, we still see a small divider line. So if we want to display transparent space, we can set color = background color or we can create a custom ItemDecoration instead of DividerItemDecoration. 
})

recycler_devices.addItemDecoration(divider)

นี่เป็นคำตอบที่มีประโยชน์
taha

7

นำมาจากการค้นหาของ Google เพิ่มรายการนี้ลงในของคุณRecyclerView:

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;


public DividerItemDecoration(Context context, AttributeSet attrs) {
    final TypedArray a = context
            .obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
    mDivider = a.getDrawable(0);
    a.recycle();
}

public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
        boolean showLastDivider) {
    this(context, attrs);
    mShowFirstDivider = showFirstDivider;
    mShowLastDivider = showLastDivider;
}

public DividerItemDecoration(Drawable divider) {
    mDivider = divider;
}

public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
        boolean showLastDivider) {
    this(divider);
    mShowFirstDivider = showFirstDivider;
    mShowLastDivider = showLastDivider;
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
        RecyclerView.State state) {
    super.getItemOffsets(outRect, view, parent, state);
    if (mDivider == null) {
        return;
    }
    if (parent.getChildPosition(view) < 1) {
        return;
    }

    if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
        outRect.top = mDivider.getIntrinsicHeight();
    } else {
        outRect.left = mDivider.getIntrinsicWidth();
    }
}

@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    if (mDivider == null) {
        super.onDrawOver(c, parent, state);
        return;
    }

    // Initialization needed to avoid compiler warning
    int left = 0, right = 0, top = 0, bottom = 0, size;
    int orientation = getOrientation(parent);
    int childCount = parent.getChildCount();

    if (orientation == LinearLayoutManager.VERTICAL) {
        size = mDivider.getIntrinsicHeight();
        left = parent.getPaddingLeft();
        right = parent.getWidth() - parent.getPaddingRight();
    } else { //horizontal
        size = mDivider.getIntrinsicWidth();
        top = parent.getPaddingTop();
        bottom = parent.getHeight() - parent.getPaddingBottom();
    }

    for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
        View child = parent.getChildAt(i);
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

        if (orientation == LinearLayoutManager.VERTICAL) {
            top = child.getTop() - params.topMargin;
            bottom = top + size;
        } else { //horizontal
            left = child.getLeft() - params.leftMargin;
            right = left + size;
        }
        mDivider.setBounds(left, top, right, bottom);
        mDivider.draw(c);
    }

    // show last divider
    if (mShowLastDivider && childCount > 0) {
        View child = parent.getChildAt(childCount - 1);
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
        if (orientation == LinearLayoutManager.VERTICAL) {
            top = child.getBottom() + params.bottomMargin;
            bottom = top + size;
        } else { // horizontal
            left = child.getRight() + params.rightMargin;
            right = left + size;
        }
        mDivider.setBounds(left, top, right, bottom);
        mDivider.draw(c);
    }
}

private int getOrientation(RecyclerView parent) {
    if (parent.getLayoutManager() instanceof LinearLayoutManager) {
        LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
        return layoutManager.getOrientation();
    } else {
        throw new IllegalStateException(
                "DividerItemDecoration can only be used with a LinearLayoutManager.");
    }
}
}

ใช้งานได้ดีกับ LinearLayoutManager เท่านั้น GridLayoutManager ควรทำอย่างไร
นักพัฒนา android

6

ลิงค์นี้ใช้งานได้อย่างมีเสน่ห์สำหรับฉัน:

https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private Drawable mDivider;
    private boolean mShowFirstDivider = false;
    private boolean mShowLastDivider = false;


    public DividerItemDecoration(Context context, AttributeSet attrs) {
        final TypedArray a = context
                .obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
            boolean showLastDivider) {
        this(context, attrs);
        mShowFirstDivider = showFirstDivider;
        mShowLastDivider = showLastDivider;
    }

    public DividerItemDecoration(Drawable divider) {
        mDivider = divider;
    }

    public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
            boolean showLastDivider) {
        this(divider);
        mShowFirstDivider = showFirstDivider;
        mShowLastDivider = showLastDivider;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
            RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (mDivider == null) {
            return;
        }
        if (parent.getChildPosition(view) < 1) {
            return;
        }

        if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
            outRect.top = mDivider.getIntrinsicHeight();
        } else {
            outRect.left = mDivider.getIntrinsicWidth();
        }
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mDivider == null) {
            super.onDrawOver(c, parent, state);
            return;
        }

        // Initialization needed to avoid compiler warning
        int left = 0, right = 0, top = 0, bottom = 0, size;
        int orientation = getOrientation(parent);
        int childCount = parent.getChildCount();

        if (orientation == LinearLayoutManager.VERTICAL) {
            size = mDivider.getIntrinsicHeight();
            left = parent.getPaddingLeft();
            right = parent.getWidth() - parent.getPaddingRight();
        } else { //horizontal
            size = mDivider.getIntrinsicWidth();
            top = parent.getPaddingTop();
            bottom = parent.getHeight() - parent.getPaddingBottom();
        }

        for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            if (orientation == LinearLayoutManager.VERTICAL) {
                top = child.getTop() - params.topMargin;
                bottom = top + size;
            } else { //horizontal
                left = child.getLeft() - params.leftMargin;
                right = left + size;
            }
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }

        // show last divider
        if (mShowLastDivider && childCount > 0) {
            View child = parent.getChildAt(childCount - 1);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            if (orientation == LinearLayoutManager.VERTICAL) {
                top = child.getBottom() + params.bottomMargin;
                bottom = top + size;
            } else { // horizontal
                left = child.getRight() + params.rightMargin;
                right = left + size;
            }
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    private int getOrientation(RecyclerView parent) {
        if (parent.getLayoutManager() instanceof LinearLayoutManager) {
            LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
            return layoutManager.getOrientation();
        } else {
            throw new IllegalStateException(
                    "DividerItemDecoration can only be used with a LinearLayoutManager.");
        }
    }
}

จากนั้นในกิจกรรมของคุณ:

mCategoryRecyclerView.addItemDecoration(
    new DividerItemDecoration(this, null));

หรือถ้าคุณใช้แฟรกเมนต์:

mCategoryRecyclerView.addItemDecoration(
    new DividerItemDecoration(getActivity(), null));

1
ใช้งานได้ดี แต่ไม่แสดงตัวแบ่งใต้รายการสุดท้ายในรายการ ฉันต้องการมันเช่นนี้mShowFirstDivider = false, mShowLastDivider = trueแต่มันจะไม่ทำงาน มีความคิดอะไรบ้าง
nightfixed

นี่ไม่สามารถจัดการ GridLayoutManager ได้ดี
นักพัฒนา android

6

เราสามารถตกแต่งไอเท็มโดยใช้เครื่องมือตกแต่งต่าง ๆ ที่ติดกับมุมมองรีไซเคิลเช่น DividerItemDecoration:

เพียงใช้สิ่งต่อไปนี้ ... นำมาจากคำตอบของEyesClear

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

private static final int[] ATTRS = new int[]{android.R.attr.listDivider};

private Drawable mDivider;

/**
 * Default divider will be used
 */
public DividerItemDecoration(Context context) {
    final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
    mDivider = styledAttributes.getDrawable(0);
    styledAttributes.recycle();
}

/**
 * Custom divider will be used
 */
public DividerItemDecoration(Context context, int resId) {
    mDivider = ContextCompat.getDrawable(context, resId);
}

@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    int left = parent.getPaddingLeft();
    int right = parent.getWidth() - parent.getPaddingRight();

    int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View child = parent.getChildAt(i);

        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

        int top = child.getBottom() + params.bottomMargin;
        int bottom = top + mDivider.getIntrinsicHeight();

        mDivider.setBounds(left, top, right, bottom);
        mDivider.draw(c);
    }
}

} จากนั้นใช้ข้างต้นดังต่อไปนี้

RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(itemDecoration);

จะแสดงตัวแบ่งระหว่างแต่ละรายการภายในรายการดังที่แสดงด้านล่าง:

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

และสำหรับผู้ที่กำลังมองหารายละเอียดเพิ่มเติมสามารถอ่านคู่มือนี้ โดยใช้ RecyclerView _ CodePath Android Cliffnotes

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

ดังนั้นทางออกที่ถูกต้องทางสุนทรียศาสตร์เพียงอย่างเดียวคือตัวหารที่ระบบทราบว่าจะใช้งานได้อย่างเหมาะสม: ระหว่างรายการ แต่ไม่สูงหรือต่ำกว่ารายการ

กรุณาแจ้งให้เราทราบข้อสงสัยใด ๆ ในความคิดเห็นด้านล่าง :)


1
นี่ไม่ได้สาธิตว่าDividerItemDecorationโค้ดดูเหมือนอย่างไร
IgorGanapolsky

1
เป็นคลาส AOSP ฉันขุดรหัสให้คุณ ..... gist.githubusercontent.com/alexfu/0f464fc3742f134ccd1e/raw/
Anudeep Samaiya

มันใช้งานไม่ได้: มันไม่ได้จัดการกับแถวที่มีความสูงต่างกัน, และมันไม่แสดงตัวแบ่งแนวตั้งสำหรับกริด
นักพัฒนา Android

5

ช้าไป แต่GridLayoutManagerฉันจะใช้สิ่งนี้:

public class GridSpacesItemDecoration : RecyclerView.ItemDecoration
{
    private int space;

    public GridSpacesItemDecoration(int space) {
        this.space = space;
    }

    public override void GetItemOffsets(Android.Graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
    {
        var position = parent.GetChildLayoutPosition(view);

        /// Only for GridLayoutManager Layouts
        var manager = parent.GetLayoutManager() as GridLayoutManager;

        if (parent.GetChildLayoutPosition(view) < manager.SpanCount)
            outRect.Top = space;

        if (position % 2 != 0) {
            outRect.Right = space;
        }

        outRect.Left = space;
        outRect.Bottom = space;
    }
}

ใช้ได้กับทุกช่วงเวลาที่คุณมี

โอลีฟ


เกี่ยวกับพื้นที่บนสุดคุณจะเปลี่ยนมันให้รองรับได้FlexboxLayoutManagerอย่างไร
นักพัฒนา Android

5

คุณสามารถเพิ่มด้วยโปรแกรมได้อย่างง่ายดาย

หาก Layout Manager ของคุณคือ Linearlayout คุณสามารถใช้:

DividerItemDecoration เป็น RecyclerView.ItemDecoration ที่สามารถใช้เป็นตัวแบ่งระหว่างรายการของ LinearLayoutManager รองรับการหมุนแนวตั้งทั้งแนวตั้งและแนวนอน

 mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
         mLayoutManager.getOrientation());
 recyclerView.addItemDecoration(mDividerItemDecoration);

แหล่ง


5

ฉันรู้สึกเหมือนมีความต้องการคำตอบง่ายๆตามโค้ดที่ไม่ได้ใช้ XML

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);

ShapeDrawable shapeDrawableForDivider = new ShapeDrawable(new RectShape());

int dividerThickness = // (int) (SomeOtherView.getHeight() * desiredPercent);
shapeDrawableForDivider.setIntrinsicHeight(dividerThickness);
shapeDrawableForDivider.setAlpha(0);

dividerItemDecoration.setDrawable(shapeDrawableForDivider);

recyclerView.addItemDecoration(dividerItemDecoration);

4

หากคุณต้องการเพิ่มพื้นที่เดียวกันสำหรับรายการวิธีที่ง่ายที่สุดคือการเพิ่มการเติมช่องว่างด้านบน + ซ้ายสำหรับ RecycleView และการเพิ่ม + ระยะขอบด้านล่างขวาให้กับรายการบัตร

dimens.xml

<resources>
    <dimen name="divider">1dp</dimen>
</resources>

list_item.xml

<CardView
 android:layout_marginBottom="@dimen/divider"
 android:layout_marginRight="@dimen/divider">
 ...
</CardView>

list.xml

<RecyclerView
 android:paddingLeft="@dimen/divider"
 android:paddingTop="@dimen/divider"
/>

4

ฉันได้เพิ่มบรรทัดในรายการตามด้านล่าง

<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/dividerColor"/>

1px จะวาดเส้นบาง ๆ

หากคุณต้องการซ่อนตัวแบ่งสำหรับแถวสุดท้ายจากนั้นdivider.setVisiblity(View.GONE);ใน onBindViewHolder สำหรับรายการสุดท้าย


1
ฉันชอบอันนี้คนอื่นก็ซับซ้อนเกินไป
Sam Chen

3

เป็นบิตที่แตกต่างจากRecyclerView ListViewที่จริงแล้วRecyclerViewความListViewต้องการโครงสร้างที่คล้ายกันในนั้น LinearLayoutยกตัวอย่างเช่น LinearLayoutมีพารามิเตอร์สำหรับการแบ่งแต่ละองค์ประกอบ ในรหัสด้านล่างฉันมีวัตถุRecyclerViewประกอบด้วยCardViewภายในLinearLayoutด้วย "padding" ที่จะทำให้พื้นที่บางส่วนระหว่างรายการ ทำให้พื้นที่นั้นเล็กมากและคุณจะได้แถว

นี่คือมุมมอง Recycler ใน recyclerview_layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".ToDoList">

    <!-- A RecyclerView with some commonly used attributes -->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/todo_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

และนี่คือลักษณะที่แต่ละรายการมีลักษณะ (และแสดงให้เห็นว่าแบ่งออกเนื่องจาก Android: การเติมเต็มใน LinearLayout ที่ล้อมรอบทุกอย่าง) ในไฟล์อื่น: cards_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    **android:padding="@dimen/activity_vertical_margin"**>
    <!-- A CardView that contains a TextView -->
    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:elevation="30dp"
        card_view:cardElevation="3dp">
            <TextView
                android:id="@+id/info_text"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                />
    </android.support.v7.widget.CardView>
</LinearLayout>

3

ทางออกที่ง่ายจริงๆคือการใช้RecyclerView-FlexibleDivider

เพิ่มการพึ่งพา:

compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'

เพิ่มใน recyclerview ของคุณ:

recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(context).build());

และคุณทำเสร็จแล้ว!


ทำงานเหมือนจับใจ ... ต้องรักการแบ่งปันโอเพ่นซอร์ส
Billy

3

1. หนึ่งในวิธีคือการใช้มุมมอง cardview และ recycler ร่วมกัน เราสามารถเพิ่มลักษณะพิเศษเช่นตัวแบ่ง อดีต https://developer.android.com/training/material/lists-cards.html

2.and อื่น ๆ โดยการเพิ่มมุมมองเป็น divider เพื่อ list_item_layout ในมุมมองของรีไซเคิล

        <View
            android:id="@+id/view1"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@color/colorAccent" />

3
public class CommonItemSpaceDecoration extends RecyclerView.ItemDecoration {

        private int mSpace = 0;
        private boolean mVerticalOrientation = true;

    public CommonItemSpaceDecoration(int space) {
        this.mSpace = space;
    }

    public CommonItemSpaceDecoration(int space, boolean verticalOrientation) {
        this.mSpace = space;
        this.mVerticalOrientation = verticalOrientation;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        outRect.top = SizeUtils.dp2px(view.getContext(), mSpace);
        if (mVerticalOrientation) {
            if (parent.getChildAdapterPosition(view) == 0) {
                outRect.set(0, SizeUtils.dp2px(view.getContext(), mSpace), 0, SizeUtils.dp2px(view.getContext(), mSpace));
            } else {
                outRect.set(0, 0, 0, SizeUtils.dp2px(view.getContext(), mSpace));
            }
        } else {
            if (parent.getChildAdapterPosition(view) == 0) {
                outRect.set(SizeUtils.dp2px(view.getContext(), mSpace), 0, 0, 0);
            } else {
                outRect.set(SizeUtils.dp2px(view.getContext(), mSpace), 0, SizeUtils.dp2px(view.getContext(), mSpace), 0);
            }
        }
    }
}

นี้จะเพิ่มพื้นที่ด้านบนของรายการทุกคนและด้านล่าง (หรือซ้ายและขวา) recyclerViewจากนั้นคุณสามารถตั้งค่าให้คุณ

recyclerView.addItemDecoration(new CommonItemSpaceDecoration(16));

SizeUtils.java

public class SizeUtils {
    public static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.