Forked from SachinR90/TimeLineIndicatorItemDecoration.java
Created
August 11, 2017 17:25
-
-
Save markus2610/1820f95dc6a3e07c4bb4310fb1e38a69 to your computer and use it in GitHub Desktop.
Exploring ItemDecoration for RecyclerView. Drawing Timelines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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