Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save markus2610/1820f95dc6a3e07c4bb4310fb1e38a69 to your computer and use it in GitHub Desktop.
Save markus2610/1820f95dc6a3e07c4bb4310fb1e38a69 to your computer and use it in GitHub Desktop.
Exploring ItemDecoration for RecyclerView. Drawing Timelines
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import static android.graphics.Paint.Cap.ROUND;
import static android.graphics.Paint.Cap.SQUARE;
import static android.graphics.Paint.Style.STROKE;
/**
* This class is used to draw following time line on RecyclerView.
* <p>
* <b>*Note</b>-Following decoration are made on recycler view<br>
* </p>
* <pre>
*
* (Content)
* |
* |
* o-----------------------
* (Content)
* | >
* |
* o-----------------------
* (Content)
* | >
* |
* o-----------------------
*
* Legend-
* o: drawCircle - draw before child in onDraw() method
* -: drawHorizontalLine - draw before child in onDraw() method
* |: drawVerticalLine - draw from top to (bottom-circleRadius) for first time.
* For rest, (top + circleRadius) to (bottom-circleRadius)
* >: drawArrow - draw arrow over items. used onDrawOver
*
* (Content): Content needs to be adjusted in the recycler view adapter as per taste
*
* </pre>
* <b>*Note</b>-
* <ul>
* <li>If needed You will have to adjust the position of the child to overlap the divider</li>
* <li>Everything comes with a catch ;-D</li>
* </ul>
* todo - Add builder pattern to create config for this class, Optimization, Unit Testing remains & lot of testing.
* <br>
* todo - Happy Coding! :-D
* <p>
* Created By <b>Sachin Rao</b> on 21-07-2017.
* </p>
*/
public class TimeLineIndicatorItemDecoration extends RecyclerView.ItemDecoration {
private static final float DP = Resources.getSystem().getDisplayMetrics().density;
private final float lineStroke = 1.5f * DP;
private final float circleRadius = 3 * DP;
private final float circleStroke = 1.5f * DP;
private final int lineColor;
private final int circleColor;
private final Paint lineCircleArrowPaint;
private Path arrowPath;
private boolean showArrow;
public TimeLineIndicatorItemDecoration() {
//set default line and circle color
this(Color.LTGRAY, Color.LTGRAY, true);
}
public TimeLineIndicatorItemDecoration(int lineColor, int circleColor, boolean showArrow) {
this.lineColor = lineColor;
this.circleColor = circleColor;
this.lineCircleArrowPaint = new Paint();
this.showArrow = showArrow;
if (this.showArrow) {
arrowPath = new Path();
}
}
public void showArrow(boolean showArrow) {
this.showArrow = showArrow;
if (!this.showArrow) {
arrowPath = null;
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
//todo draw arrow
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int itemCount = parent.getAdapter().getItemCount();
final int left = (int) (parent.getPaddingLeft()+(10*DP));
final int right = parent.getWidth() - parent.getPaddingRight();
//to draw below each child we will need the child's bottom. and draw for every child
for (int i = 0; i < itemCount; i++) {
final View child = parent.getChildAt(i);
if (child == null) { //null check
continue;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getTop() + params.topMargin;
final int bottom = child.getBottom();
//draw horizontal line
drawHorizontalLine(c, left + circleRadius, bottom, right, bottom);
//draw vertical line
if (i == 0) {
drawVerticalLine(c, left, top, left, bottom - circleRadius);
} else {
drawVerticalLine(c, left, top + circleRadius, left, bottom - circleRadius);
}
//draw circle
drawCircle(c, left + child.getPaddingLeft(), bottom, circleRadius);
}
super.onDraw(c, parent, state);
}
private void drawHorizontalLine(Canvas c, float x1, float y1, float x2, int y2) {
//make paint configuration here
configPaint(lineStroke, STROKE, ROUND, lineColor);
//finally draw line
c.drawLine(x1, y1, x2, y2, lineCircleArrowPaint);
}
private void drawCircle(Canvas c, float left, float top, float circleRadius) {
//make paint configuration here
configPaint(circleStroke, STROKE, ROUND, circleColor);
//finally draw circle
c.drawCircle(left, top, circleRadius, lineCircleArrowPaint);
}
private void drawVerticalLine(Canvas c, float x1, float y1, float x2, float y2) {
//make paint configuration here
configPaint(lineStroke, STROKE, ROUND, lineColor);
//finally draw line
c.drawLine(x1, y1, x2, y2, lineCircleArrowPaint);
}
private void drawArrow(Canvas c, float centerX, float centerY, float topX, float topY, float bottomX, float bottomY) {
if (!showArrow) {
return;
}
if (arrowPath == null) {
return;
}
//make paint configuration here
//hardcoded dp and circle color for now
configPaint(3 * DP, STROKE, SQUARE, circleColor);
arrowPath.reset();
arrowPath.moveTo(topX, topY);
arrowPath.lineTo(centerX, centerY);
arrowPath.lineTo(bottomX, bottomY);
//close the loop if you want to change the style of arrow
c.drawPath(arrowPath, lineCircleArrowPaint);
}
/**
* config paint
*
* @param strokeWidth stroke width for paint
* @param style type of for paint
* @param cap for paint
* @param color for the paint
*/
private void configPaint(float strokeWidth, Paint.Style style, Paint.Cap cap, int color) {
lineCircleArrowPaint.setStrokeWidth(strokeWidth);
lineCircleArrowPaint.setStyle(style);
lineCircleArrowPaint.setStrokeCap(cap);
lineCircleArrowPaint.setColor(color);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment