RecycleView间距的设置
RecyclerView没有可以直接设置间距的属性,但是提供了一个ItemDecoration的类来装饰一个item,默认情况下使用recycleView的item是没有间距和分割线的,要添加间距可以自己写个SpaceItemDecoration类继承ItemDecoration:
ItemDecoration类的使用
ItemDecoration类主要是三个方法:
public void onDraw(Canvas c, RecyclerView parent, State state)
public void onDrawOver(Canvas c, RecyclerView parent, State state)
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
- onDraw(),可以实现类似绘制背景的效果,内容在上面。(如绘制item的分割线)
- onDrawOver(),可以绘制在内容的上面,覆盖内容。(如给item添加覆盖在上面的角标等)
- getItemOffsets(),可以实现类似padding的效果
一般绘制分割线需onDraw()和getItemOffsets();而仅仅是添加间距的话只用getItemOffsets()就可以实现。
LinearLayoutManager添加间距
private void setLinearLayoutSpaceItemDecoration(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
} else {
outRect.top = 0;
}
}
效果图:
GridLayoutManager 或者 StaggeredGridLayoutManager添加间距
说明:这个方法适配了三列以上item时以及添加有头布局时的等间距,每个item的左右padding通过动态计算保证了每个item的左右padding和相同(这样item的内容宽度就都相同,网上的很多方法都是先给每个item添加左边padding,然后判断最后一列的时候添加右padding,这样会导致最后一列即添加了左边距又添加了右边距,边距是等分了,但是由于outRect方法添加边距是占用item的空间的所以最后一列多加了右边距自然item的内容就少了一个右边距的宽度。)
private void setGridLayoutSpaceItemDecoration(Rect outRect, View view, RecyclerView parent, RecyclerView.State state){
int position = parent.getChildAdapterPosition(view) - headItemCount;
if (headItemCount != 0 && position == - headItemCount){
return;
}
int column = position % spanCount;
if (includeEdge) {
outRect.left = space - column * space / spanCount;
outRect.right = (column + 1) * space / spanCount;
if (position < spanCount) {
outRect.top = space;
}
outRect.bottom = space;
} else {
outRect.left = column * space / spanCount;
outRect.right = space - (column + 1) * space / spanCount;
if (position >= spanCount) {
outRect.top = space;
}
}
}
效果图:
说明
关于GridLayoutManager 或者 StaggeredGridLayoutManager添加间距的方法是通用,如果仅仅简单的添加边距或者没有边距相同这些要求可以直接通过设置item布局的padding或者margin再配合recycleView的padding和margin来解决。
附源码
import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* good programmer.
*
* @data : 2018-01-11 下午 03:28
* @author: futia
* @email : futianyi1994@126.com
* @description : RecyclerView 设置间距
*/
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
public static final int LINEARLAYOUT = 0;
public static final int GRIDLAYOUT = 1;
public static final int STAGGEREDGRIDLAYOUT = 2;
//限定为LINEARLAYOUT,GRIDLAYOUT,STAGGEREDGRIDLAYOUT
@IntDef({LINEARLAYOUT, GRIDLAYOUT,STAGGEREDGRIDLAYOUT})
//表示注解所存活的时间,在运行时,而不会存在. class 文件.
@Retention(RetentionPolicy.SOURCE)
public @interface LayoutManager {
public int type() default LINEARLAYOUT;
}
private int leftRight;
private int topBottom;
/**
* 头布局个数
*/
private int headItemCount;
/**
* 边距
*/
private int space;
/**
* 时候包含边距
*/
private boolean includeEdge;
/**
* 烈数
*/
private int spanCount;
private @LayoutManager int layoutManager;
/**
* GridLayoutManager or StaggeredGridLayoutManager spacing
* @param leftRight
* @param topBottom
* @param headItemCount
* @param layoutManager
*/
public SpaceItemDecoration(int leftRight, int topBottom, int headItemCount, @LayoutManager int layoutManager) {
this.leftRight = leftRight;
this.topBottom = topBottom;
this.headItemCount = headItemCount;
this.layoutManager = layoutManager;
}
/**
* GridLayoutManager or StaggeredGridLayoutManager spacing
* @param space
* @param includeEdge
* @param layoutManager
*/
public SpaceItemDecoration(int space,boolean includeEdge, @LayoutManager int layoutManager) {
this(space, 0, includeEdge, layoutManager);
}
/**
* GridLayoutManager or StaggeredGridLayoutManager spacing
* @param space
* @param headItemCount
* @param includeEdge
* @param layoutManager
*/
public SpaceItemDecoration(int space,int headItemCount,boolean includeEdge, @LayoutManager int layoutManager) {
this.space = space;
this.headItemCount = headItemCount;
this.includeEdge = includeEdge;
this.layoutManager = layoutManager;
}
/**
* GridLayoutManager or StaggeredGridLayoutManager spacing
* @param space
* @param headItemCount
* @param layoutManager
*/
public SpaceItemDecoration(int space,int headItemCount, @LayoutManager int layoutManager) {
this(space, headItemCount, true, layoutManager);
}
/**
* LinearLayoutManager or GridLayoutManager or StaggeredGridLayoutManager spacing
* @param space
* @param layoutManager
*/
public SpaceItemDecoration(int space, @LayoutManager int layoutManager) {
this(space, 0, true, layoutManager);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
switch (layoutManager) {
case LINEARLAYOUT:
setLinearLayoutSpaceItemDecoration(outRect,view,parent,state);
break;
case GRIDLAYOUT:
GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();
//列数
spanCount = gridLayoutManager.getSpanCount();
setNGridLayoutSpaceItemDecoration(outRect,view,parent,state);
break;
case STAGGEREDGRIDLAYOUT:
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) parent.getLayoutManager();
//列数
spanCount = staggeredGridLayoutManager.getSpanCount();
setNGridLayoutSpaceItemDecoration(outRect,view,parent,state);
break;
default:
break;
}
}
/**
* LinearLayoutManager spacing
*
* @param outRect
* @param view
* @param parent
* @param state
*/
private void setLinearLayoutSpaceItemDecoration(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
} else {
outRect.top = 0;
}
}
/**
* GridLayoutManager or StaggeredGridLayoutManager spacing
* @param outRect
* @param view
* @param parent
* @param state
*/
private void setNGridLayoutSpaceItemDecoration(Rect outRect, View view, RecyclerView parent, RecyclerView.State state){
int position = parent.getChildAdapterPosition(view) - headItemCount;
if (headItemCount != 0 && position == - headItemCount){
return;
}
int column = position % spanCount;
if (includeEdge) {
outRect.left = space - column * space / spanCount;
outRect.right = (column + 1) * space / spanCount;
if (position < spanCount) {
outRect.top = space;
}
outRect.bottom = space;
} else {
outRect.left = column * space / spanCount;
outRect.right = space - (column + 1) * space / spanCount;
if (position >= spanCount) {
outRect.top = space;
}
}
}
/**
* GridLayoutManager设置间距(此方法最左边和最右边间距为设置的一半)
*
* @param outRect
* @param view
* @param parent
* @param state
*/
private void setGridLayoutSpaceItemDecoration(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
//判断总的数量是否可以整除
int totalCount = layoutManager.getItemCount();
int surplusCount = totalCount % layoutManager.getSpanCount();
int childPosition = parent.getChildAdapterPosition(view);
//竖直方向的
if (layoutManager.getOrientation() == GridLayoutManager.VERTICAL) {
if (surplusCount == 0 && childPosition > totalCount - layoutManager.getSpanCount() - 1) {
//后面几项需要bottom
outRect.bottom = topBottom;
} else if (surplusCount != 0 && childPosition > totalCount - surplusCount - 1) {
outRect.bottom = topBottom;
}
//被整除的需要右边
if ((childPosition + 1 - headItemCount) % layoutManager.getSpanCount() == 0) {
//加了右边后最后一列的图就非宽度少一个右边距
//outRect.right = leftRight;
}
outRect.top = topBottom;
outRect.left = leftRight / 2;
outRect.right = leftRight / 2;
} else {
if (surplusCount == 0 && childPosition > totalCount - layoutManager.getSpanCount() - 1) {
//后面几项需要右边
outRect.right = leftRight;
} else if (surplusCount != 0 && childPosition > totalCount - surplusCount - 1) {
outRect.right = leftRight;
}
//被整除的需要下边
if ((childPosition + 1) % layoutManager.getSpanCount() == 0) {
outRect.bottom = topBottom;
}
outRect.top = topBottom;
outRect.left = leftRight;
}
}
}