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


938

这是一个示例,该示例演示了如何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"/>

但是,我在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"/>

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



@EyesClear添加项目<TextView />另一个XML,并在列表Same Activity中使用它。
Amitsharma 2015年

7
支持lib中有一个类,com.homeretailgroup.argos.android.view.decorators.DividerItemDecoration可以这样使用它:mRecyclerView.addItemDecoration(new DividerItemDecoration(activity, LinearLayoutManager.VERTICAL));
fada21 '16

您可以为垂直列表的列表项添加底边距,也许可以将其用作分隔线?
resw67

最简单的方法是在适配器行的第一项周围添加顶部/底部页边距。android:layout_marginBottom =“ 4dp”。(请注意将边距添加到父级布局不会削减它。)
pstorli,

Answers:


1224

2016年10月更新

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

DividerItemDecoration是RecyclerView.ItemDecoration,可以用作的项之间的分隔线LinearLayoutManager。它同时支持HORIZONTALVERTICAL方向。

用法:

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

先前的答案

一些答案要么使用自那以后就已弃用的方法,要么不提供完整的解决方案,因此我尝试进行简短的最新总结。


不同于ListViewRecyclerView该类没有与分隔符相关的参数。相反,您需要扩展ItemDecoration一个RecyclerView的内部类:

一个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.topoutRect.left以及outRect.right对预期效果的性质。

分频器 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);
        }
    }
}

您可以调用第一个使用默认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>

注意:如果要在项目上绘制分隔线onDrawOver()改用method。

用法

要使用新类add VerticalSpaceItemDecorationDividerSpaceItemDecorationto 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 2015年

1
我想知道使用Paint而不是创建可绘制对象是个好主意吗?然后,我可以打电话canvas.drawLine(startX, startY, stopX, stopY, mPaint)onDrawOver?有任何性能差异吗?
Arst

1
仅提供参考性的评论:如果您打算稍后在列表中添加项目,请始终在最后一项添加空格。如果您不这样做,那么在添加项目时,该项目将没有空间。感谢VerticalSpace!
Tsuharesu 2015年

24
如果项目完全不透明,则如上所示的DividerItemDecoration将不起作用,分隔线将被项目覆盖。在这种情况下,您还需要覆盖getItemOffsets()并将底部偏移量添加到outRect中,以便分隔符最终位于项目之外。另外,您可以重写onDrawOver()而不是onDraw()来绘制分隔符。
jpop

115
最好在整页代码中添加分隔符到recyclerView。Google,真可惜。
注意7j 2016年

480

只需添加

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

另外,您可能需要添加依赖项
compile 'com.android.support:recyclerview-v7:27.1.0'

编辑:

为了对其进行一点自定义,您可以添加一个自定义可绘制对象:

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

您可以自由使用任何自定义可绘制对象,例如:

<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 '18

这必须是正确的答案。请把getActivity改为上下文。
Jhon Fredy Trujillo Ortega,2018年

另外,最好从LayoutManager获取方向。
lsrom '18

谢谢!您也可以使用Configuration垂直分隔线:if (orientation == Configuration.ORIENTATION_LANDSCAPE) { recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL)); } else { recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));}
AlexS

3
好的答案,但它在最后一项之后也添加了一个分隔符。
CoolMind

256

我是否可以将您的注意力转移到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;
}

我确定可以进行其他样式设置,但这是一个起点。:)


如何添加替换这些内容:“ footerDividersEnabled”,“ headerDividersEnabled”,“ listSelector”,“ fastScrollEnabled”,“ smoothScrollbar”,“ textFilterEnabled”?
Android开发人员

关于如何放置样式的任何输入?
nizam.sp 2014年

要设置此解决方案的样式,您需要覆盖主题中的“ android:listDivider”属性
Pavel Dudka 2014年

1
分频器不适用于RecyclerView。您需要使用RecyclerView.itemDecoration。看到这个答案:stackoverflow.com/a/27664023/2311451
Cocorico

3
为什么分隔线会扩大物品的整个宽度?如何显示在规格google.com/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 2015年

26
getChildPosition现在已弃用,getChildAdapterPosition可以代替使用。
EyesClear 2015年

4
不要忘记(像我一样)删除对的调用super.getItemOffsets,否则您的偏移量将被覆盖。
jayeffkay 2015年

@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,2015年

36
当心透支!
2016年

@shem你能详细说明吗?
RominaV 2016年

7
在Android上几层上一层(活动背景,回收视图背景和项目视图背景)进行绘制时-Android将它们全部绘制,也对用户不可见。所谓的透支可能会影响您的效果,请点击此处了解更多信息:youtube.com/watch?
v=T52v50r

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>

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-要在项目之间增加间距,
您只需要在项目视图中添加padding属性

<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)
埃里克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创建的行没有遵循,这很让人分心和难看。因此,我将使用您的解决方案。
米歇尔(Michel)

您如何处理最后一个项目?
oldgod

@oldergod。您指出了正确的痛点。我首先会同意在最后一项上也有分隔线的设计。但是,如果您不想要那样。为此视图分配一个ID,如果位置最后一个,则将其隐藏在bindView中。
Javanator

@Javanator我认为可以,我采用的方法相同。谢谢。
oldgod

最简单就是最好
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

由于没有正确的方法来正确地使用Material Design来实现此目的,因此我做了以下技巧,直接在列表项上添加了分隔符:

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

在获得一些材料设计的高程信息后,DividerItemDecoration停止工作(以获得与Inbox中相同的效果);简单的事情太复杂了。该解决方案简单有效。
DenisGL '16

20

我处理Divider视图以及Divider插入的方式是通过添加RecyclerView扩展。

1。

通过命名View或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的Activity或Fragment上,可以通过调用以下命令来设置自定义可绘制对象:

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可绘制资源在哪里包含:

<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

对于那些只在项目之间寻找空格的人,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.");
        }
    }
}

dimens.xml

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

11

为您的视图增加一个边距,对我有用。

android:layout_marginTop="10dp"

如果您只想添加相等的间距并要使用XML进行设置,只需将padding您要充气的项目设置为RecyclerView等号,然后让背景色确定间距颜色即可。layoutMarginRecyclerView


3
尽管这可以解决问题,但这不是正确的答案,例如,因为在不对行布局进行任何其他操作的情况下无法解决问题,而且,在顶部出现空白x1,在行之间出现空白x2。
Sreekanth Karumanaghat

这不是一个好主意,因为在overscroll列表末尾拉动时的效果将被不必要地填充到应用于填充的位置RecyclerView
AeroEchelon

最好将项目的布局包装在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

  <?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答案在onDraw中初始化int,并且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搜索中获取,将此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.");
    }
}
}

这仅适用于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 = falsemShowLastDivider = true,但它不会工作。知道为什么吗?
2015年

这不能很好地处理GridLayoutManager。
Android开发人员

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

然后使用以下内容

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

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

如果您的布局管理器是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上隐藏最后一个列表Item。


1
我喜欢这个,其他人太复杂了。
山姆·陈

3

RecyclerView距离有点不同ListView。实际上,其中RecyclerView需要ListView类似的结构。例如,一个LinearLayout。的LinearLayout具有用于每个元件分割参数。在下面的代码中,我包含一个对象,其中RecyclerView包含CardView一个LinearLayout带有“填充” 的对象,该填充将在项目之间放置一些空间。使该空间很小,您会得到一条线。

这是recyclerview_layout.xml中的Recycler视图

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

这是每个项目的外观(由于包围了所有内容的LinearLayout中的android:padding,因此每个项目看起来都一样)。在另一个文件中: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 view结合使用, 我们可以轻松地添加效果,如分隔线。例如 https://developer.android.com/training/material/lists-cards.html

2.另一个是通过将视图作为分隔器添加到回收器视图的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);
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.