itslonua
10/25/2017 - 10:53 AM

Add equal spacing to RecyclerView items automatically. Can handle horizontal, vertical, and grid display modes

Add equal spacing to RecyclerView items automatically. Can handle horizontal, vertical, and grid display modes

BEFORE

AFTER

// Automatically infer display orientation of items
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.addItemDecoration(new EqualSpacingItemDecoration(16)); // 16px. In practice, you'll want to use getDimensionPixelSize

// Explicitly specify display orientation of items.
// Available display modes:
//   - HORIZONTAL
//   - VERTICAL
//   - GRID
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.addItemDecoration(new EqualSpacingItemDecoration(16, EqualSpacingItemDecoration.HORIZONTAL)); // 16px. In practice, you'll want to use getDimensionPixelSize
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class EqualSpacingItemDecoration extends RecyclerView.ItemDecoration {
  private final int spacing;
  private int displayMode;

  public static final int HORIZONTAL = 0;
  public static final int VERTICAL = 1;
  public static final int GRID = 2;

  public EqualSpacingItemDecoration(int spacing) {
    this(spacing, -1);
  }

  public EqualSpacingItemDecoration(int spacing, int displayMode) {
    this.spacing = spacing;
    this.displayMode = displayMode;
  }

  @Override
  public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    int position = parent.getChildViewHolder(view).getAdapterPosition();
    int itemCount = state.getItemCount();
    RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
    setSpacingForDirection(outRect, layoutManager, position, itemCount);
  }

  private void setSpacingForDirection(Rect outRect,
                                      RecyclerView.LayoutManager layoutManager,
                                      int position,
                                      int itemCount) {
    
    // Resolve display mode automatically
    if (displayMode == -1) {
      displayMode = resolveDisplayMode(layoutManager);
    }

    switch (displayMode) {
      case HORIZONTAL:
        outRect.left = spacing;
        outRect.right = position == itemCount - 1 ? spacing : 0;
        outRect.top = spacing;
        outRect.bottom = spacing;
        break;
      case VERTICAL:
        outRect.left = spacing;
        outRect.right = spacing;
        outRect.top = spacing;
        outRect.bottom = position == itemCount - 1 ? spacing : 0;
        break;
      case GRID:
        if (layoutManager instanceof GridLayoutManager) {
          GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
          int cols = gridLayoutManager.getSpanCount();
          int rows = itemCount / cols;

          outRect.left = spacing;
          outRect.right = position % cols == cols - 1 ? spacing : 0;
          outRect.top = spacing;
          outRect.bottom = position / cols == rows - 1 ? spacing : 0;
        }
        break;
    }
  }

  private int resolveDisplayMode(RecyclerView.LayoutManager layoutManager) {
    if (layoutManager instanceof GridLayoutManager) return GRID;
    if (layoutManager.canScrollHorizontally()) return HORIZONTAL;
    return VERTICAL;
  }
}