1:分割线的使用
1.1LinearLayoutManager时分割线使用
RecyclerView设置分割线的方法:
public void addItemDecoration(@NonNull RecyclerView.ItemDecoration decor) {
this.addItemDecoration(decor, -1);
}
如果只需要一条灰色的线,如上调用recyclerView的addItemDecoration方法传入ItemDecoration即可。
这里RecyclerView为我们提供了DividerItemDecoration。这个类继承自ItemDecoration,内部方法十分简单,设置分割线的 orientation以及传入一个drawable。
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
或者传入drawable
DividerItemDecoration dividerItemDecoration= new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.ic_launcher_background));
recyclerView.addItemDecoration(dividerItemDecoration);
1.1GridLayoutManager分割线使用
类似于LinearLayoutManager ,我们可以直接添加两个addItemDecoration,分别传入横向和纵向:
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.HORIZONTAL));
看下效果:
效果不是特别好,我们希望item的底部不需要线或者不想要这样的效果,要怎么做呢?
我们知道DividerItemDecoration是继承自ItemDecoration,那我们是不是也可以重写class继承ItemDecoration呢?
答案是:可以。
首先我们看下ItemDecoration的结构。
public abstract static class ItemDecoration {
public ItemDecoration() {
}
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
this.onDraw(c, parent);
}
/** @deprecated */
@Deprecated
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent) {
}
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
this.onDrawOver(c, parent);
}
/** @deprecated */
@Deprecated
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent) {
}
/** @deprecated */
@Deprecated
public void getItemOffsets(@NonNull Rect outRect, int itemPosition, @NonNull RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
this.getItemOffsets(outRect, ((RecyclerView.LayoutParams)view.getLayoutParams()).getViewLayoutPosition(), parent);
}
}
如上是recyclerview中ItemDecoration的各个属性。
我们用的有两个方法 onDraw和getItemOffsets。
ondraw中绘制横向和纵向的分割线,其中我们需要判断是否绘制item的横向和纵向的分割线。
定义属性:
//是否绘制横向和纵向的分割线。
boolean isDrawHorDivider;
boolean isDrawVerDivider;
其次,我们根据获取到的view的位置,来判断是否绘制该view的横向和纵向分割线。
//获取子view个数
int childCount=parent.getChildCount();
//获取spanCount
int spanCount= ((GridLayoutManager)(parent.getLayoutManager())).getSpanCount();
int orientation=((GridLayoutManager)(parent.getLayoutManager())).getOrientation();
获取到子view的个数以及gridlayoutManager的spanCount后,我们来判断是否绘制。
int extra=childCount%spanCount==0?spanCount:childCount%spanCount;
上面这个值是计算出来的一个偏移量,用子view的数量-extra获取的值,如果小于子view的position。
那就说明,这个子view会于recyclerView的最后一行或者最后一列。(横向和纵向的grid)
所以,判断是否绘制时,我们也需要分开来判断orientation。
for (int i=0;i<childCount;i++){
isDrawHorDivider=true;
isDrawVerDivider=true;
// 最右侧一列不绘制竖直方向
if (orientation== OrientationHelper.VERTICAL&&(i+1)%spanCount==0){
isDrawVerDivider=false;
}
//最后一行不绘制横向分割线
if (orientation== OrientationHelper.VERTICAL&&i>=(childCount-extra)){
isDrawHorDivider=false;
}
//水平方向时 如果是底部一行 不绘制横向
if (orientation== OrientationHelper.HORIZONTAL&&(i+1)%spanCount==0){
isDrawHorDivider=false;
}
//水平方向时 如果是右侧一列 不绘制纵向
if (orientation== OrientationHelper.HORIZONTAL&&i>=(childCount-extra)){
isDrawVerDivider=false;
}
//绘制部分。。。
}
是否绘制判断完了,接着我们来编写绘制分割线的代码。
这里分为两块,分别的drawHorizontal和drawVertical。
我们从onDraw中获取三个参数,分别是canvas,recyclerView和position。
绘制drawable我们先setBound,所以先分别确定left,top,right以及bottom。
代码如下:
public void drawVertical(Canvas canvas,RecyclerView parent,int position){
View childView =parent.getChildAt(position);
RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) childView.getLayoutParams();
/**
* &&&&&&&&&&&&&&&&&
* & &
* & * * &
* & * * &
* & &
* &&&&&&&&&&&&&&&&&
*
* 如上回字型 中间 表示子view 外层是layoutParam的margins
* 在右侧绘制drawable时:
* view的top= childView.getTop-param.topMargin;
* view的left=childView.getRight+param.rightMargin;
* view的right=left+drawable的宽度
* view的bottom=childView.getBottom+param.bottomMargin+drawable的高度
* */
int top=childView.getTop()-params.topMargin;
int left=childView.getRight()+params.rightMargin;
int right=left+drawable.getIntrinsicWidth();
int bottom=childView.getBottom()+params.bottomMargin+drawable.getIntrinsicHeight();
drawable.setBounds(left,top,right,bottom);
drawable.draw(canvas);
}
横向的和上面类似,整体代码如下:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* create by zj on 2019/6/20
*/
public class MyGridDivider extends RecyclerView.ItemDecoration {
private Drawable drawable;
public MyGridDivider(Drawable drawable){
this.drawable=drawable;
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
//获取子view个数
int childCount=parent.getChildCount();
//获取spanCount
int spanCount= ((GridLayoutManager)(parent.getLayoutManager())).getSpanCount();
int orientation=((GridLayoutManager)(parent.getLayoutManager())).getOrientation();
//是否绘制横向和纵向的分割线。
boolean isDrawHorDivider;
boolean isDrawVerDivider;
int extra=childCount%spanCount==0?spanCount:childCount%spanCount;
for (int i=0;i<childCount;i++){
isDrawHorDivider=true;
isDrawVerDivider=true;
// 最右侧一列不绘制竖直方向
if (orientation== OrientationHelper.VERTICAL&&(i+1)%spanCount==0){
isDrawVerDivider=false;
}
//最后一行不绘制横向分割线
if (orientation== OrientationHelper.VERTICAL&&i>=(childCount-extra)){
isDrawHorDivider=false;
}
//水平方向时 如果是底部一行 不绘制横向
if (orientation== OrientationHelper.HORIZONTAL&&(i+1)%spanCount==0){
isDrawHorDivider=false;
}
//水平方向时 如果是右侧一列 不绘制纵向
if (orientation== OrientationHelper.HORIZONTAL&&i>=(childCount-extra)){
isDrawVerDivider=false;
}
if (isDrawVerDivider){
drawVertical(c,parent,i);
}
if (isDrawHorDivider){
drawHorizontal(c,parent,i);
}
}
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
//获取spanCount
int spanCount= ((GridLayoutManager)(parent.getLayoutManager())).getSpanCount();
int orientation=((GridLayoutManager)(parent.getLayoutManager())).getOrientation();
//getChildViewHolderInt获取位置
int position=parent.getChildLayoutPosition(view);
if (orientation==OrientationHelper.VERTICAL&&(position+1)%spanCount==0){
outRect.set(0,0,0,drawable.getIntrinsicHeight());
return;
}
if (orientation==OrientationHelper.HORIZONTAL&&(position+1)%spanCount==0){
outRect.set(0,0,drawable.getIntrinsicWidth(),0);
return;
}
outRect.set(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
}
public void drawVertical(Canvas canvas,RecyclerView parent,int position){
View childView =parent.getChildAt(position);
RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) childView.getLayoutParams();
/**
* &&&&&&&&&&&&&&&&&
* & &
* & * * &
* & * * &
* & &
* &&&&&&&&&&&&&&&&&
*
* 如上回字型 中间 表示子view 外层是layoutParam的margins
* 在右侧绘制drawable时:
* view的top= childView.getTop-param.topMargin;
* view的left=childView.getRight+param.rightMargin;
* view的right=left+drawable的宽度
* view的bottom=childView.getBottom+param.bottomMargin+drawable的高度
* */
int top=childView.getTop()-params.topMargin;
int left=childView.getRight()+params.rightMargin;
int right=left+drawable.getIntrinsicWidth();
int bottom=childView.getBottom()+params.bottomMargin+drawable.getIntrinsicHeight();
drawable.setBounds(left,top,right,bottom);
drawable.draw(canvas);
}
public void drawHorizontal(Canvas canvas,RecyclerView parent,int position){
View childView =parent.getChildAt(position);
RecyclerView.LayoutParams params= (RecyclerView.LayoutParams) childView.getLayoutParams();
int top=childView.getBottom()+params.bottomMargin;
int left=childView.getLeft()-params.leftMargin;
int right=childView.getRight()+params.rightMargin+drawable.getIntrinsicWidth();
int bottom=top+drawable.getIntrinsicHeight();
drawable.setBounds(left,top,right,bottom);
drawable.draw(canvas);
}
}
最后我们看下效果:
2:设置动画
可以通过调用setItemAnimator属性,设置动画。
如下是设置动画的源码。
public void setItemAnimator(@Nullable RecyclerView.ItemAnimator animator) {
if (this.mItemAnimator != null) {
this.mItemAnimator.endAnimations();
this.mItemAnimator.setListener((RecyclerView.ItemAnimator.ItemAnimatorListener)null);
}
this.mItemAnimator = animator;
if (this.mItemAnimator != null) {
this.mItemAnimator.setListener(this.mItemAnimatorListener);
}
}
RecyclerView提供了默认的ItemAnimator实现类:DefaultItemAnimator。如果没有特殊的需求,默认使用这个动画即可。