如何在RecyclerView中的项目之间添加分隔符和空格?

Eye*_*ear 883 android divider android-recyclerview

这是一个如何ListView使用dividerdividerHeight参数在类中执行的示例:

<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"/>
Run Code Online (Sandbox Code Playgroud)

但是,我没有在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"/>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,可以直接定义边距和/或将自定义分隔视图添加到列表项的布局中,还是有更好的方法来实现我的目标?

Eye*_*ear 1159

2016年10月更新

Android支持库版本25.0.0引入了DividerItemDecoration类:

DividerItemDecoration是一个RecyclerView.ItemDecoration,可用作LinearLayoutManager项目之间的分隔符.它支持HORIZONTAL和VERTICAL方向.

用法:

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
    layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
Run Code Online (Sandbox Code Playgroud)

以前的答案

有些答案要么使用已被弃用的方法,要么不提供完整的解决方案,所以我尝试做一个简短的最新总结.


与此类不同LinearLayoutManager,HORIZONTAL该类没有与分隔符相关的参数.相反,你需要扩展VERTICAL,一个ListView内部类:

ItemDecoration允许应用程序从适配器的数据集向特定项视图添加特殊的绘图和布局偏移.这对于在项目,突出显示,可视分组边界等之间绘制分隔符非常有用.

所有ItemDecorations都按照它们添加的顺序绘制,在项目视图之前(在onDraw()中)和项目之后(在onDrawOver(Canvas,RecyclerView,RecyclerView.State)中).

垂直间距 RecyclerView

扩展ItemDecoration,添加自定义构造函数,将空间高度作为参数并覆盖RecyclerView方法:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您不想在最后一项下面插入空格,请添加以下条件:

if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
            outRect.bottom = verticalSpaceHeight;
}
Run Code Online (Sandbox Code Playgroud)

注意:您还可以修改ItemDecoration,ItemDecorations以及onDraw()对预期效果的性质.

分频器 Canvas

扩展RecyclerView和覆盖RecyclerView.State)方法:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以调用第一个使用默认Android分隔符属性的构造函数,也可以调用第二个使用自己的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>
Run Code Online (Sandbox Code Playgroud)

注意:如果你想得出的分隔您的项目,覆盖Vertical方法来代替.

用法

若要使用新的类添加ItemDecorationItemDecorationheight,例如在片段的getItemOffsets()方法:

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;
}
Run Code Online (Sandbox Code Playgroud)

还有Lucas Rocha的图书馆,它应该简化项目装饰过程.虽然没试过.

功能包括:

  • 库存项目装饰品的集合,包括:
  • 项目间距水平/垂直分隔线.
  • 项目清单

  • 将divider添加到recyclerView的整页代码是最佳答案.耻辱你,谷歌. (97认同)
  • 如果项目完全不透明,上面显示的DividerItemDecoration将不起作用,分隔符将被项目透支.在这种情况下,您还需要覆盖getItemOffsets()并将底部偏移添加到outRect,以便分隔符在项目之外结束.或者,您可以覆盖onDrawOver()而不是onDraw()来绘制分隔符以更改项目. (22认同)
  • @droppin_science如果我错了,请纠正我,但我不在`onDraw()`中创建任何对象.我只是引用已经存在的实例. (3认同)

Leo*_*der 445

只需添加

recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
                DividerItemDecoration.VERTICAL));
Run Code Online (Sandbox Code Playgroud)

您还可能需要添加依赖项
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));
Run Code Online (Sandbox Code Playgroud)

您可以自由使用任何自定义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>
Run Code Online (Sandbox Code Playgroud)

  • 不错的答案,但它也在最后一项之后添加了一个分隔符。 (7认同)
  • 这应该是正确答案。Plz,将 getActivity 更改为上下文。 (2认同)

Duy*_*yen 253

我可能会把你的注意力转移到Alex Fu的Github上的这个特定文件: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;
}
Run Code Online (Sandbox Code Playgroud)

我确信可以做更多的造型,但这是一个起点.:)

  • 如何用你的代码设置`20dp dividerHeight`? (6认同)
  • 为什么分隔器会扩展项目的整个宽度?如何在规格中显示http://www.google.com/design/spec/components/lists.html#lists-specs (3认同)

Ser*_*eyA 154

简单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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `getChildPosition`现已弃用,可以使用`getChildAdapterPosition`代替. (26认同)
  • 不要忘记(就像我一样)删除对`super.getItemOffsets`的调用,否则你的偏移将被覆盖. (4认同)
  • 这是否实现了以像素为单位的间距? (2认同)

Mad*_*ota 105

简单的一个是为RecyclerView设置背景颜色,为项目设置不同的背景颜色.这是一个例子......

<android.support.v7.widget.RecyclerView
    android:background="#ECEFF1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:scrollbars="vertical"/>
Run Code Online (Sandbox Code Playgroud)

TextView项(它可以是任何东西),底边距为"x"dp或px.

<TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="1dp"
    android:background="#FFFFFF"/>
Run Code Online (Sandbox Code Playgroud)

输出 ...

在此输入图像描述

  • 小心透支! (36认同)
  • 当Android中的几个图层一个接一个地绘制时(活动背景,循环视图背景和项目视图背景) - Android将它们全部绘制出来,也是用户不可见的那些.这称为透支,可能会影响您的表现,更多关于它的信息:https://www.youtube.com/watch?v = T52v50r-JfE (7认同)
  • 什么伎俩!只需要在加载时保持列表为白色。 (2认同)

Gen*_*ani 42

我处理 Divider 视图和 Divider Insets 的方式是添加 RecyclerView 扩展。

1.

通过命名 View 或 RecyclerView 添加一个新的扩展文件:

RecyclerViewExtension.kt
Run Code Online (Sandbox Code Playgroud)

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

在这里你可以指定左,右android:insetLeftandroid:insetRight

3.

在初始化 RecyclerView 的 Activity 或 Fragment 上,您可以通过调用来设置自定义 drawable:

recyclerView.setDivider(R.drawable.recycler_view_divider)
Run Code Online (Sandbox Code Playgroud)

4.

干杯

带分隔线的 RecyclerView 行。


Bel*_*lom 41

我认为使用简单的分隔符可以帮助您

为每个项添加分隔符:
1-将其添加到可绘制目录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>
Run Code Online (Sandbox Code Playgroud)

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


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()));
 ....
 }
Run Code Online (Sandbox Code Playgroud)


4-要在Items之间添加间距,
只需在项目视图中添加填充属性即可

<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>
Run Code Online (Sandbox Code Playgroud)

  • resources.getDrawable()现已弃用.您可以传入上下文并使用ContextCompat.getDrawable(context,R.drawable.line_divider) (2认同)

Jav*_*tor 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"/>
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,这是我的救星:http://stackoverflow.com/a/30386358/2086460 (2认同)

小智 25

这很简单,你不需要这么复杂的代码

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

在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>
Run Code Online (Sandbox Code Playgroud)


Yoa*_*uet 21

由于没有正确的方法来使用Material Design正确实现这一点,我只是通过以下技巧直接在列表项上添加分隔符:

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/dividerColor"/>
Run Code Online (Sandbox Code Playgroud)


Pra*_*ngh 16

如果有人想要仅添加项目之间的10dp间距,则可以通过将drawable设置为DividerItemDecoration:

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

dividerItemDecoration.setDrawable(
    ContextCompat.getDrawable(getContext(), R.drawable.divider_10dp)
); 
Run Code Online (Sandbox Code Playgroud)

divider_10dp可绘制资源在哪里包含:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <size android:height="10dp"/>
    <solid android:color="@android:color/transparent"/>
</shape>
Run Code Online (Sandbox Code Playgroud)


fri*_*day 15

2016年10月更新

使用支持库v25.0.0,最终可以使用基本水平和垂直分隔线的默认实现!

https://developer.android.com/reference/android/support/v7/widget/DividerItemDecoration.html


小智 11

为您的视图添加边距,它对我有用.

android:layout_marginTop="10dp"
Run Code Online (Sandbox Code Playgroud)

如果您只想添加相等的间距并希望以XML格式进行,只需设置paddingRecyclerViewlayoutMargin您膨胀的项目相等的数量RecyclerView,然后让背景颜色确定间距颜色.

  • 虽然这可行,但这不是正确的答案,例如,因为这不能解决问题而不对行布局做额外的事情,同样,在顶部边缘x1将出现,在行之间将出现边距x2. (3认同)

Rya*_*ral 11

对于那些谁正在寻找只为项目之间的空间RecyclerView看到我的方法你在哪里得到的所有项目之间的间隔相等,但在我给了一个更大的填充第一项和最后一项.我只在水平方向上向左/向右应用填充,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.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

dimens.xml

<resources>
    <dimen name="paddingItemDecorationDefault">10dp</dimen>
    <dimen name="paddingItemDecorationEdge">20dp</dimen>
</resources>
Run Code Online (Sandbox Code Playgroud)


tur*_*oid 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>
    
    Run Code Online (Sandbox Code Playgroud)

在drawable文件夹中创建以下shape_border.xml

  <?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>
Run Code Online (Sandbox Code Playgroud)

这是最终结果 - 带分频器的RecyclerView.

这是最终结果 - 带分频器的RecyclerView.


Kev*_*ant 10

这实际上并没有解决问题,但作为一种临时解决方法,您可以在XML布局中设置卡上的useCompatPadding属性,使其与Lollipop前版本的测量值相同.

card_view:cardUseCompatPadding="true"
Run Code Online (Sandbox Code Playgroud)


Lea*_* ES 9

我从旧的gist中分叉了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();
    }
}
Run Code Online (Sandbox Code Playgroud)

2)将装饰器添加到RecylerView:

recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));
Run Code Online (Sandbox Code Playgroud)

  • 这个仓库修复了它:https://github.com/devunwired/recyclerview-playground (2认同)

Pha*_*inh 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)
Run Code Online (Sandbox Code Playgroud)

  • 这是有用的答案 (2认同)

Boo*_*unz 7

我觉得需要一个不使用 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);
Run Code Online (Sandbox Code Playgroud)

我非常喜欢这个答案,我用单表达式 Kotlin 答案重写了它:

    recyclerView.addItemDecoration(DividerItemDecoration(this,DividerItemDecoration.VERTICAL).also { deco ->
        with (ShapeDrawable(RectShape())){
            intrinsicHeight = (resources.displayMetrics.density * 24).toInt()
            alpha = 0
            deco.setDrawable(this)
        }
    })
Run Code Online (Sandbox Code Playgroud)

这与@Nerdy 的原始答案做同样的事情,除了它将分隔线的高度设置为 24dp 而不是另一个视图高度的百分比。


Wes*_*y92 7

这是一个装饰,可让您设置项目之间的间距以及边缘的间距。这适用于HORIZONTALVERTICAL布局。

class LinearSpacingDecoration(
    @Px private val itemSpacing: Int,
    @Px private val edgeSpacing: Int = 0
): RecyclerView.ItemDecoration() {
    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        val count = parent.adapter?.itemCount ?: 0
        val position = parent.getChildAdapterPosition(view)
        val leading = if (position == 0) edgeSpacing else itemSpacing
        val trailing = if (position == count - 1) edgeSpacing else 0
        outRect.run {
            if ((parent.layoutManager as? LinearLayoutManager)?.orientation == LinearLayout.VERTICAL) {
                top = leading
                bottom = trailing
            } else {
                left = leading
                right = trailing
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

recyclerView.addItemDecoration(LinearSpacingDecoration(itemSpacing = 10, edgeSpacing = 20))
Run Code Online (Sandbox Code Playgroud)


gat*_*xyz 6

从谷歌搜索中获取,将此ItemDecoration添加到您的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.");
    }
}
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*cro 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.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的活动中:

mCategoryRecyclerView.addItemDecoration(
    new DividerItemDecoration(this, null));
Run Code Online (Sandbox Code Playgroud)

或者如果您使用的是片段:

mCategoryRecyclerView.addItemDecoration(
    new DividerItemDecoration(getActivity(), null));
Run Code Online (Sandbox Code Playgroud)


Anu*_*iya 6

我们可以使用附加到recyclerview的各种装饰器来装饰物品,例如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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用上面的内容如下

RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(itemDecoration);
Run Code Online (Sandbox Code Playgroud)

这将在列表中的每个项目之间显示分隔符,如下所示:

在此输入图像描述

对于那些正在寻找更多细节的人,可以查看本指南 使用RecyclerView _ CodePath Android Cliffnotes

这里的一些答案建议使用边距,但问题是:如果你同时添加顶部和底部边距,它们将在项目之间添加,并且它们将太大.如果只添加其中一个,则整个列表的顶部或底部都没有边距.如果在顶部添加一半距离,在底部添加一半,则外边距将太小.

因此,唯一美学上正确的解决方案是系统知道正确应用位置的分隔线:项目之间但不高于或低于项目.

请在下面的评论中告诉我任何疑问:)


lim*_*ium 5

如果要为项目添加相同的空间,最简单的方法是为RecycleView卡片项目添加上边距+左边距和右边距+下边距。

文件dimens.xml

<resources>
    <dimen name="divider">1dp</dimen>
</resources>
Run Code Online (Sandbox Code Playgroud)

文件list_item.xml

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

    ...
</CardView>
Run Code Online (Sandbox Code Playgroud)

文件list.xml

<RecyclerView
    ...
    android:paddingLeft="@dimen/divider"
    android:paddingTop="@dimen/divider" />
Run Code Online (Sandbox Code Playgroud)


Oll*_*vel 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这项工作适用于您拥有的任何跨度计数。

奥莉


Bey*_*yaz 5

您可以通过编程轻松添加。

如果您的布局管理器是Linearlayout,则可以使用:

DividerItemDecoration是RecyclerView.ItemDecoration,可以用作LinearLayoutManager的项目之间的分隔线。它同时支持水平和垂直方向。

 mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
         mLayoutManager.getOrientation());
 recyclerView.addItemDecoration(mDividerItemDecoration);
Run Code Online (Sandbox Code Playgroud)

资源


wiz*_*hen 5

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将在每个项目的顶部和底部(或左侧和右侧)添加空间。然后您可以将其设置为您的recyclerView.

recyclerView.addItemDecoration(new CommonItemSpaceDecoration(16));
Run Code Online (Sandbox Code Playgroud)

文件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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*vid 5

最新的方法是这个,例如在 Fragment 的 onCreateView 中使用:

        val recyclerView = rootView.findViewById<RecyclerView>(R.id.recycler_view)
        recyclerView.adapter = mListAdapter
        recyclerView.layoutManager = LinearLayoutManager(context)
        rootView.context.let {
            val dividerItemDecoration = MaterialDividerItemDecoration(
                it,
                MaterialDividerItemDecoration.VERTICAL
            )
            dividerItemDecoration.isLastItemDecorated = false

            // https://github.com/material-components/material-components-android/blob/master/docs/components/Divider.md
            // Needed if you did not set colorOnSurface in your theme because otherwise the default color would be pink_900 -> default according to Material should be colorOnSurface (12% opacity applied automatically on top).
//            dividerItemDecoration.setDividerColorResource(it, R.color.colorDivider)

            recyclerView.addItemDecoration(dividerItemDecoration)
        }
Run Code Online (Sandbox Code Playgroud)

我想你可以忘记之前所有其他的解决方案。