在使用RecyclerView组件加载数据列表时,产品和美工为了美观都会在每一个item项之间添加分割线,分割线的实现方式一般分为两种,第一种是在布局文件中通过添加<View ...></View>组件,然后在代码中通过方法setVisibility()设置其是否可见,实现分割线效果。
下面一种是通过装饰器为RecyclerView列表的item添加分割线,代码很简单:
-
//找到RecyclerView组件
-
RecyclerView mCommonRvList = rootView.findViewById(R.id.common_recyclerview_list);
-
//添加装饰器
-
mCommonRvList.addItemDecoration(
new MyDividerItemDecoration(getContext(),DividerItemDecoration.VERTICAL));
其中MyDividerItemDecoration类是对Android.support.v7.widget包源码类DividerItemDecoration.java一份拷贝后的稍作改动,源码如下:
-
package android.support.v7.widget;
-
-
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.annotation.NonNull;
-
import android.util.Log;
-
import android.view.View;
-
import android.widget.LinearLayout;
-
-
/**
-
* DividerItemDecoration is a {@link RecyclerView.ItemDecoration} that can be used as a divider
-
* between items of a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and
-
* {@link #VERTICAL} orientations.
-
*
-
* <pre>
-
* mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
-
* mLayoutManager.getOrientation());
-
* recyclerView.addItemDecoration(mDividerItemDecoration);
-
* </pre>
-
*/
-
public
class DividerItemDecoration extends RecyclerView.ItemDecoration {
-
public
static
final
int HORIZONTAL = LinearLayout.HORIZONTAL;
-
public
static
final
int VERTICAL = LinearLayout.VERTICAL;
-
-
private
static
final String TAG =
"DividerItem";
-
private
static
final
int[] ATTRS =
new
int[]{ android.R.attr.listDivider };
-
-
private Drawable mDivider;
-
-
/**
-
* Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}.
-
*/
-
private
int mOrientation;
-
-
private
final Rect mBounds =
new Rect();
-
-
/**
-
* Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a
-
* {@link LinearLayoutManager}.
-
*
-
* @param context Current context, it will be used to access resources.
-
* @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}.
-
*/
-
public DividerItemDecoration(Context context, int orientation) {
-
final TypedArray a = context.obtainStyledAttributes(ATTRS);
-
mDivider = a.getDrawable(
0);
-
if (mDivider ==
null) {
-
Log.w(TAG,
"@android:attr/listDivider was not set in the theme used for this "
-
+
"DividerItemDecoration. Please set that attribute all call setDrawable()");
-
}
-
a.recycle();
-
setOrientation(orientation);
-
}
-
-
/**
-
* Sets the orientation for this divider. This should be called if
-
* {@link RecyclerView.LayoutManager} changes orientation.
-
*
-
* @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
-
*/
-
public void setOrientation(int orientation) {
-
if (orientation != HORIZONTAL && orientation != VERTICAL) {
-
throw
new IllegalArgumentException(
-
"Invalid orientation. It should be either HORIZONTAL or VERTICAL");
-
}
-
mOrientation = orientation;
-
}
-
-
/**
-
* Sets the {@link Drawable} for this divider.
-
*
-
* @param drawable Drawable that should be used as a divider.
-
*/
-
public void setDrawable(@NonNull Drawable drawable) {
-
if (drawable ==
null) {
-
throw
new IllegalArgumentException(
"Drawable cannot be null.");
-
}
-
mDivider = drawable;
-
}
-
-
@Override
-
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
-
if (parent.getLayoutManager() ==
null || mDivider ==
null) {
-
return;
-
}
-
if (mOrientation == VERTICAL) {
-
drawVertical(c, parent);
-
}
else {
-
drawHorizontal(c, parent);
-
}
-
}
-
-
private void drawVertical(Canvas canvas, RecyclerView parent) {
-
canvas.save();
-
final
int left;
-
final
int right;
-
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
-
if (parent.getClipToPadding()) {
-
left = parent.getPaddingLeft();
-
right = parent.getWidth() - parent.getPaddingRight();
-
canvas.clipRect(left, parent.getPaddingTop(), right,
-
parent.getHeight() - parent.getPaddingBottom());
-
}
else {
-
left =
0;
-
right = parent.getWidth();
-
}
-
-
final
int childCount = parent.getChildCount();
-
for (
int i =
0; i < childCount; i++) {
-
final View child = parent.getChildAt(i);
-
parent.getDecoratedBoundsWithMargins(child, mBounds);
-
final
int bottom = mBounds.bottom + Math.round(child.getTranslationY());
-
final
int top = bottom - mDivider.getIntrinsicHeight();
-
mDivider.setBounds(left, top, right, bottom);
-
mDivider.draw(canvas);
-
}
-
canvas.restore();
-
}
-
-
private void drawHorizontal(Canvas canvas, RecyclerView parent) {
-
canvas.save();
-
final
int top;
-
final
int bottom;
-
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
-
if (parent.getClipToPadding()) {
-
top = parent.getPaddingTop();
-
bottom = parent.getHeight() - parent.getPaddingBottom();
-
canvas.clipRect(parent.getPaddingLeft(), top,
-
parent.getWidth() - parent.getPaddingRight(), bottom);
-
}
else {
-
top =
0;
-
bottom = parent.getHeight();
-
}
-
-
final
int childCount = parent.getChildCount();
-
for (
int i =
0; i < childCount; i++) {
-
final View child = parent.getChildAt(i);
-
parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
-
final
int right = mBounds.right + Math.round(child.getTranslationX());
-
final
int left = right - mDivider.getIntrinsicWidth();
-
mDivider.setBounds(left, top, right, bottom);
-
mDivider.draw(canvas);
-
}
-
canvas.restore();
-
}
-
-
@Override
-
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-
RecyclerView.State state) {
-
if (mDivider ==
null) {
-
outRect.set(
0,
0,
0,
0);
-
return;
-
}
-
if (mOrientation == VERTICAL) {
-
outRect.set(
0,
0,
0, mDivider.getIntrinsicHeight());
-
}
else {
-
outRect.set(
0,
0, mDivider.getIntrinsicWidth(),
0);
-
}
-
}
-
}
注意其中,RecyclerView列表在设置布局管理器时,使用的是线性布局管理器LinearLayoutManager。
-
private void drawVertical(Canvas canvas, RecyclerView parent) {
-
canvas.save();
-
final
int left;
-
final
int right;
-
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
-
if (parent.getClipToPadding()) {
-
//注意这里,分割线绘制的宽度是否填充整个屏幕的宽度是跟RecyclerView组件所在parent父布局是否设置paddingLeft和paddingRight相关的
-
left = parent.getPaddingLeft();
-
right = parent.getWidth() - parent.getPaddingRight();
-
canvas.clipRect(left, parent.getPaddingTop(), right,
-
parent.getHeight() - parent.getPaddingBottom());
-
}
else {
-
left =
0;
-
right = parent.getWidth();
-
}
-
-
final
int childCount = parent.getChildCount();
-
for (
int i =
0; i < childCount; i++) {
-
final View child = parent.getChildAt(i);
-
parent.getDecoratedBoundsWithMargins(child, mBounds);
-
final
int bottom = mBounds.bottom + Math.round(child.getTranslationY());
-
final
int top = bottom - mDivider.getIntrinsicHeight();
-
mDivider.setBounds(left, top, right, bottom);
-
mDivider.draw(canvas);
-
}
-
canvas.restore();
-
}
上面方法的注释处:分割线绘制的宽度是否填充整个屏幕的宽度是跟RecyclerView组件所在parent父布局是否设置paddingLeft和paddingRight相关的,如果我们不想让分割线整个填充屏幕的宽度,就需要设置RecyclerView组件所在父布局parent的padding值,如下添加 android:paddingRight="10dp"和android:paddingLeft="10dp":
-
<?xml version="1.0" encoding="utf-8"?>
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-
android:layout_width=
"fill_parent"
-
android:layout_height=
"wrap_content"
-
android:layout_marginTop=
"10dp"
-
android:layout_marginLeft=
"5dp"
-
android:layout_marginRight=
"5dp"
-
android:paddingRight=
"10dp"
-
android:paddingLeft=
"10dp"
-
android:orientation=
"vertical">
-
-
<android.support.v7.widget.RecyclerView
-
android:id=
"@+id/common_recyclerview_list"
-
android:layout_width=
"match_parent"
-
android:layout_height=
"wrap_content"
-
/>
-
</LinearLayout>
这个android:paddingRight="10dp"和android:paddingLeft="10dp"值的大小不宜设置过大,否则将影响整个列表内边距的样式,但是设置这个值的绘制后分割线绘制的宽度填充的还是太宽,于是就想办法把上面的源码类DividerItemDecoration.java重新继承一下,修改画分割线宽度的代码:
-
private void drawVertical(Canvas canvas, RecyclerView parent) {
-
canvas.save();
-
final
int left;
-
final
int right;
-
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
-
if (parent.getClipToPadding()) {
-
//注意这里,分割线绘制的宽度是否填充整个屏幕的宽度是跟RecyclerView组件所在parent父布局是否设置paddingLeft和paddingRight相关的
-
left = parent.getPaddingLeft()+
18;
-
right = parent.getWidth() - parent.getPaddingRight()-
18;
-
canvas.clipRect(left, parent.getPaddingTop(), right,
-
parent.getHeight() - parent.getPaddingBottom());
-
}
else {
-
left =
0;
-
right = parent.getWidth();
-
}
-
-
final
int childCount = parent.getChildCount();
-
for (
int i =
0; i < childCount; i++) {
-
final View child = parent.getChildAt(i);
-
parent.getDecoratedBoundsWithMargins(child, mBounds);
-
final
int bottom = mBounds.bottom + Math.round(child.getTranslationY());
-
final
int top = bottom - mDivider.getIntrinsicHeight();
-
mDivider.setBounds(left, top, right, bottom);
-
mDivider.draw(canvas);
-
}
-
canvas.restore();
-
}
整个代码如下:
-
package com.jsmcc.ui.myaccount.view;
-
-
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.annotation.NonNull;
-
import android.support.v7.widget.LinearLayoutManager;
-
import android.support.v7.widget.RecyclerView;
-
import android.util.Log;
-
import android.view.View;
-
import android.widget.LinearLayout;
-
-
import com.jsmcc.utils.DensityUtil;
-
-
/**
-
* MyDividerItemDecoration is a {@link RecyclerView.ItemDecoration} that can be used as a divider
-
* between items of a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and
-
* {@link #VERTICAL} orientations.
-
*
-
* <pre>
-
* mDividerItemDecoration = new MyDividerItemDecoration(recyclerView.getContext(),
-
* mLayoutManager.getOrientation());
-
* recyclerView.addItemDecoration(mDividerItemDecoration);
-
* </pre>
-
*/
-
public
class MyDividerItemDecoration extends RecyclerView.ItemDecoration {
-
public
static
final
int HORIZONTAL = LinearLayout.HORIZONTAL;
-
public
static
final
int VERTICAL = LinearLayout.VERTICAL;
-
-
private
static
final String TAG =
"DividerItem";
-
private
static
final
int[] ATTRS =
new
int[]{ android.R.attr.listDivider };
-
-
private Drawable mDivider;
-
private Context mContext;
-
-
/**
-
* Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}.
-
*/
-
private
int mOrientation;
-
-
private
final Rect mBounds =
new Rect();
-
-
/**
-
* Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a
-
* {@link LinearLayoutManager}.
-
*
-
* @param context Current context, it will be used to access resources.
-
* @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}.
-
*/
-
public MyDividerItemDecoration(Context context, int orientation) {
-
final TypedArray a = context.obtainStyledAttributes(ATTRS);
-
mDivider = a.getDrawable(
0);
-
if (mDivider ==
null) {
-
Log.w(TAG,
"@android:attr/listDivider was not set in the theme used for this "
-
+
"MyDividerItemDecoration. Please set that attribute all call setDrawable()");
-
}
-
a.recycle();
-
setOrientation(orientation);
-
}
-
-
/**
-
* Sets the orientation for this divider. This should be called if
-
* {@link RecyclerView.LayoutManager} changes orientation.
-
*
-
* @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
-
*/
-
public void setOrientation(int orientation) {
-
if (orientation != HORIZONTAL && orientation != VERTICAL) {
-
throw
new IllegalArgumentException(
-
"Invalid orientation. It should be either HORIZONTAL or VERTICAL");
-
}
-
mOrientation = orientation;
-
}
-
-
/**
-
* Sets the {@link Drawable} for this divider.
-
*
-
* @param drawable Drawable that should be used as a divider.
-
*/
-
public void setDrawable(@NonNull Drawable drawable) {
-
if (drawable ==
null) {
-
throw
new IllegalArgumentException(
"Drawable cannot be null.");
-
}
-
mDivider = drawable;
-
}
-
-
@Override
-
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
-
if (parent.getLayoutManager() ==
null || mDivider ==
null) {
-
return;
-
}
-
if (mOrientation == VERTICAL) {
-
drawVertical(c, parent);
-
}
else {
-
drawHorizontal(c, parent);
-
}
-
}
-
-
private void drawVertical(Canvas canvas, RecyclerView parent) {
-
canvas.save();
-
final
int left;
-
final
int right;
-
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
-
if (parent.getClipToPadding()) {
-
left = parent.getPaddingLeft()+
18;
-
right = parent.getWidth() - parent.getPaddingRight()-
18;
-
canvas.clipRect(left, parent.getPaddingTop(), right,
-
parent.getHeight() - parent.getPaddingBottom());
-
}
else {
-
left =
0;
-
right = parent.getWidth();
-
}
-
-
final
int childCount = parent.getChildCount();
-
for (
int i =
0; i < childCount; i++) {
-
final View child = parent.getChildAt(i);
-
parent.getDecoratedBoundsWithMargins(child, mBounds);
-
final
int bottom = mBounds.bottom + Math.round(child.getTranslationY());
-
final
int top = bottom - mDivider.getIntrinsicHeight();
-
mDivider.setBounds(left, top, right, bottom);
-
mDivider.draw(canvas);
-
}
-
canvas.restore();
-
}
-
-
private void drawHorizontal(Canvas canvas, RecyclerView parent) {
-
canvas.save();
-
final
int top;
-
final
int bottom;
-
//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
-
if (parent.getClipToPadding()) {
-
top = parent.getPaddingTop();
-
bottom = parent.getHeight() - parent.getPaddingBottom();
-
canvas.clipRect(parent.getPaddingLeft(), top,
-
parent.getWidth() - parent.getPaddingRight(), bottom);
-
}
else {
-
top =
0;
-
bottom = parent.getHeight();
-
}
-
-
final
int childCount = parent.getChildCount();
-
for (
int i =
0; i < childCount; i++) {
-
final View child = parent.getChildAt(i);
-
parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
-
final
int right = mBounds.right + Math.round(child.getTranslationX());
-
final
int left = right - mDivider.getIntrinsicWidth();
-
mDivider.setBounds(left, top, right, bottom);
-
mDivider.draw(canvas);
-
}
-
canvas.restore();
-
}
-
-
@Override
-
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-
RecyclerView.State state) {
-
if (mDivider ==
null) {
-
outRect.set(
0,
0,
0,
0);
-
return;
-
}
-
if (mOrientation == VERTICAL) {
-
outRect.set(
0,
0,
0, mDivider.getIntrinsicHeight());
-
}
else {
-
outRect.set(
0,
0, mDivider.getIntrinsicWidth(),
0);
-
}
-
}
-
}
-
运行代码,这样成功的实现了产品要求的效果!
总结:
① 为列表组件添加装饰器:
//添加装饰器
mCommonRvList.addItemDecoration(new MyDividerItemDecoration(getContext(),DividerItemDecoration.VERTICAL));
② 为列表组件的父布局添加padding,如上;
③ 将MyDividerItemDecoration.java 拷贝到你的项目里,在①处new 创建就可以了。
如有更好的方法欢迎留言指正!不胜感激!
推荐一篇很好的文章:https://blog.csdn.net/lmj623565791/article/details/45059587
转载:https://blog.csdn.net/luqingshuai_eloong/article/details/106192741