RecyclerView 一些知识点

  • 一、设置元素边距
  • padding:
  • 分割线
  • 标签
  • 二、设置左右滑动删除以及长按上下移动


一、设置元素边距

由于RecyclerView 没有像listview一样的divider 属性,所以需要用recyclerView.addItemDecoration() 方法来设置 元素之间的间距。

自定义类 继承 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)

官方源码虽然都写的很清楚,但还不少小伙伴不知道怎么理解,怎么用或用哪个方法,下面我画个简单的图来帮你们理解一下。

RecyclerView横向布局固定4个item不够4个就居中显示_拖拽


ItemDecoration

图画的丑请见谅,首先我们假设绿色区域代表的是我们的内容,红色区域代表我们自己绘制的装饰,可以看到:

图1:代表了getItemOffsets(),可以实现类似padding的效果

图2:代表了onDraw(),可以实现类似绘制背景的效果,内容在上面

图3:代表了onDrawOver(),可以绘制在内容的上面,覆盖内容

应用场景:

padding:

public class SimplePaddingDecoration extends RecyclerView.ItemDecoration {

    private int dividerHeight;


    public SimplePaddingDecoration(Context context) {
        dividerHeight = context.getResources().getDimensionPixelSize(R.dimen.divider_height);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.bottom = dividerHeight;//类似加了一个bottom padding
    }
}
recyclerView.addItemDecoration(new SimplePaddingDecoration(this));

效果如下:

RecyclerView横向布局固定4个item不够4个就居中显示_拖拽_02

分割线

getItemOffsets 方法只能设置边距,颜色默认为背景色,无法重新设置。如果要主动设置颜色,则需要配合 onDraw() 方法

public class SimpleDividerDecoration extends RecyclerView.ItemDecoration {

    private int dividerHeight;
    private Paint dividerPaint;

    public SimpleDividerDecoration(Context context) {
        dividerPaint = new Paint();
        dividerPaint.setColor(context.getResources().getColor(R.color.colorAccent));
        dividerHeight = context.getResources().getDimensionPixelSize(R.dimen.divider_height);
    }


    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.bottom = dividerHeight;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int childCount = parent.getChildCount();
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        for (int i = 0; i < childCount - 1; i++) {
            View view = parent.getChildAt(i);
            float top = view.getBottom();
            float bottom = view.getBottom() + dividerHeight;
            c.drawRect(left, top, right, bottom, dividerPaint);
        }
    }
}

效果如下:

RecyclerView横向布局固定4个item不够4个就居中显示_边距_03

标签

现在很多电商app会给商品加上一个标签,比如“推荐”,“热卖”,“秒杀”等等,可以看到这些标签都是覆盖在内容之上的,这就可以用onDrawOver()来实现,我们这里简单实现一个有趣的标签

public class LeftAndRightTagDecoration extends RecyclerView.ItemDecoration {
    private int tagWidth;
    private Paint leftPaint;
    private Paint rightPaint;

    public LeftAndRightTagDecoration(Context context) {
        leftPaint = new Paint();
        leftPaint.setColor(context.getResources().getColor(R.color.colorAccent));
        rightPaint = new Paint();
        rightPaint.setColor(context.getResources().getColor(R.color.colorPrimary));
        tagWidth = context.getResources().getDimensionPixelSize(R.dimen.tag_width);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            int pos = parent.getChildAdapterPosition(child);
            boolean isLeft = pos % 2 == 0;
            if (isLeft) {
                float left = child.getLeft();
                float right = left + tagWidth;
                float top = child.getTop();
                float bottom = child.getBottom();
                c.drawRect(left, top, right, bottom, leftPaint);
            } else {
                float right = child.getRight();
                float left = right - tagWidth;
                float top = child.getTop();
                float bottom = child.getBottom();
                c.drawRect(left, top, right, bottom, rightPaint);

            }
        }
    }
}

效果如下:

RecyclerView横向布局固定4个item不够4个就居中显示_android_04


链接: 参考路径.

二、设置左右滑动删除以及长按上下移动

使用类:ItemTouchHelper,构造方法中需要传入ItemTouchHelper.Callback 对象,所以需要我们手动实现类继承ItemTouchHelper.Callback:
主要需要重写三个方法:
1.getMovementFlags() 定义 item 的可以拖拽和滑动的方向。
2.onMove() 当 item 想要上下拖拽时会调用此方法。
3.onSwiped 当 item 想要左右侧滑时会调用此方法。

public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback {
 
  private IItemTouchHelperAdapter mAdapter;
 
  public MyItemTouchHelperCallback(IItemTouchHelperAdapter mAdapter) {
    this.mAdapter = mAdapter;
  }
 
  @Override
  public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    //上下拖拽,若有其他需求同理
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    //向右侧滑,若有其他需求同理
    int swipeFlags = ItemTouchHelper.RIGHT;
    return makeMovementFlags(dragFlags, swipeFlags);
  }
 
  @Override
  public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    //通知Adapter更新数据和视图
    mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    //若返回false则表示不支持上下拖拽
    return true;
  }
 
  @Override
  public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    //通知Adapter更新数据和视图
    mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
  }
   
  @Override
  public boolean isItemViewSwipeEnabled() {
    //是否可以左右侧滑,默认返回true
    return true;
  }
 
  @Override
  public boolean isLongPressDragEnabled() {
    //是否可以长按上下拖拽,默认返回false
    return true;
  }
}

适配器中的回调方法,用户拖拽事件和侧滑事件,可以先定义一个回调的接口,

public interface IItemTouchHelperAdapter {
  /**
   * 当item被移动时调用
   *
   * @param fromPosition 被操作的item的起点
   * @param toPosition  被操作的item的终点
   */
  void onItemMove(int fromPosition, int toPosition);
 
  /**
   * 当item被侧滑时调用
   *
   * @param position 被侧滑的item的position
   */
  void onItemDismiss(int position);
}

适配器中的实现

@Override
 public void onItemMove(int fromPosition, int toPosition) {
 //更改元素位置
   Collections.swap(mList, fromPosition, toPosition);
   notifyItemMoved(fromPosition, toPosition);
 }
 
 @Override
 public void onItemDismiss(int position) {
 //删除元素
   mList.remove(position);
   notifyItemRemoved(position);
 }

链接: 参考路径.