package com.timehop.stickyheadersrecyclerview.rendering; import android.graphics.Canvas; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.LinearLayout; import com.timehop.stickyheadersrecyclerview.calculation.DimensionCalculator; import com.timehop.stickyheadersrecyclerview.util.OrientationProvider; /** * Responsible for drawing headers to the canvas provided by the item decoration */ public class HeaderRenderer { private final DimensionCalculator mDimensionCalculator; private final OrientationProvider mOrientationProvider; public HeaderRenderer(OrientationProvider orientationProvider) { this(orientationProvider, new DimensionCalculator()); } private HeaderRenderer(OrientationProvider orientationProvider, DimensionCalculator dimensionCalculator) { mOrientationProvider = orientationProvider; mDimensionCalculator = dimensionCalculator; } /** * Draws a header to a canvas, offsetting by some x and y amount * * @param recyclerView the parent recycler view for drawing the header into * @param canvas the canvas on which to draw the header * @param header the view to draw as the header * @param offset a Rect used to define the x/y offset of the header. Specify x/y offset by setting * the {@link Rect#left} and {@link Rect#top} properties, respectively. */ public void drawHeader(RecyclerView recyclerView, Canvas canvas, View header, Rect offset) { canvas.save(); if (recyclerView.getLayoutManager().getClipToPadding()) { // Clip drawing of headers to the padding of the RecyclerView. Avoids drawing in the padding Rect clipRect = getClipRectForHeader(recyclerView, header); canvas.clipRect(clipRect); } canvas.translate(offset.left, offset.top); header.draw(canvas); canvas.restore(); } /** * Gets a clipping rect for the header based on the margins of the header and the padding of the * recycler. * FIXME: Currently right margin in VERTICAL orientation and bottom margin in HORIZONTAL * orientation are clipped so they look accurate, but the headers are not being drawn at the * correctly smaller width and height respectively. * * @param recyclerView for which to provide a header * @param header for clipping * @return a {@link Rect} for clipping a provided header to the padding of a recycler view */ private Rect getClipRectForHeader(RecyclerView recyclerView, View header) { Rect headerMargins = mDimensionCalculator.getMargins(header); if (mOrientationProvider.getOrientation(recyclerView) == LinearLayout.VERTICAL) { return new Rect( recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(), recyclerView.getWidth() - recyclerView.getPaddingRight() - headerMargins.right, recyclerView.getHeight() - recyclerView.getPaddingBottom()); } else { return new Rect( recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(), recyclerView.getWidth() - recyclerView.getPaddingRight(), recyclerView.getHeight() - recyclerView.getPaddingBottom() - headerMargins.bottom); } } }