public class GridAndListLayout extends TwoWayLayoutManager { private final int NUM_LANES = 2; public GridAndListLayout(Context context, Orientation orientation) { super(context, orientation); } private boolean isGridItem(int position) { return position < 4; } private int getLaneForPosition(int position) { if (isGridItem(position)) { return position % NUM_LANES; } return 0; } private int getLayoutInnerStart() { final View firstChild = getChildAt(0); final int firstPosition = getPosition(firstChild); final int offset; if (getLaneForPosition(firstPosition) > 0) { if (getOrientation() == Orientation.VERTICAL) { offset = getDecoratedMeasuredHeight(firstChild); } else { offset = getDecoratedMeasuredWidth(firstChild); } } else { offset = 0; } return getLayoutStart() + offset; } private int getLayoutInnerEnd() { final View lastChild = getChildAt(getChildCount() - 1); final int lastPosition = getPosition(lastChild); final int offset; if (isGridItem(lastPosition) && getLaneForPosition(lastPosition) < NUM_LANES - 1) { if (getOrientation() == Orientation.VERTICAL) { offset = getDecoratedMeasuredHeight(lastChild); } else { offset = getDecoratedMeasuredWidth(lastChild); } } else { offset = 0; } return getLayoutEnd() - offset; } @Override protected void measureChild(View child, Direction direction) { int widthUsed = 0; int heightUsed = 0; if (isGridItem(getPosition(child))) { if (getOrientation() == Orientation.VERTICAL) { widthUsed = (getWidth() - getPaddingLeft() - getPaddingRight()) / 2; } else { heightUsed = (getHeight() - getPaddingTop() - getPaddingBottom()) / 2; } } measureChildWithMargins(child, widthUsed, heightUsed); } @Override protected void layoutChild(View child, Direction direction) { final int width = getDecoratedMeasuredWidth(child); final int height = getDecoratedMeasuredHeight(child); final int position = getPosition(child); final int gridLane = getLaneForPosition(position); final boolean isVertical = (getOrientation() == Orientation.VERTICAL); final boolean isGridItem = isGridItem(position); final int gridOffset; if (isGridItem) { gridOffset = (isVertical ? width : height) * gridLane; } else { gridOffset = 0; } int l, t, r, b; if (isVertical) { l = getPaddingLeft() + gridOffset; t = (direction == Direction.END ? getLayoutEnd() : getLayoutStart() - height); } else { l = (direction == Direction.END ? getLayoutEnd() : getLayoutStart() - width); t = getPaddingTop() + gridOffset; } if (isGridItem) { if (direction == Direction.END && gridLane > 0) { if (isVertical) { t -= height; } else { l -= width; } } else if (direction == Direction.START && gridLane < NUM_LANES - 1) { if (isVertical) { t += height; } else { l += width; } } } r = l + width; b = t + height; layoutDecorated(child, l, t, r, b); } @Override protected boolean canAddMoreViews(Direction direction, int limit) { if (direction == Direction.END) { return getLayoutInnerEnd() < getEndWithPadding(); } else { return getLayoutInnerStart() > getStartWithPadding(); } }