Skip to content

Instantly share code, notes, and snippets.

@vinaysshenoy
Created November 9, 2015 10:53
Show Gist options
  • Save vinaysshenoy/30acf9b42d688e476b3e to your computer and use it in GitHub Desktop.
Save vinaysshenoy/30acf9b42d688e476b3e to your computer and use it in GitHub Desktop.
Android DividerView
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DividerView">
<attr name="dashGap" format="dimension" />
<attr name="dashWidth" format="dimension" />
<attr name="dashColor" format="color" />
<attr name="dashThickness" format="dimension" />
<attr name="orientation" format="enum">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
</declare-styleable>
</resources>
package com.vinaysshenoy.widget;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PointF;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.IntDef;
import android.util.AttributeSet;
import android.view.View;
import com.vinaysshenoy.R;
/**
* Widget that can be used to draw a vertical or horizontal line
* <p/>
* Created by vinaysshenoy on 09/11/15.
*/
public class DividerView extends View {
@IntDef({ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL})
public @interface Orientation {
}
public static final int ORIENTATION_HORIZONTAL = 0;
public static final int ORIENTATION_VERTICAL = 1;
private static final int DEFAULT_ORIENTATION = ORIENTATION_HORIZONTAL;
private static final int DEFAULT_DASH_GAP = 1; //dips
private static final int DEFAULT_DASH_WIDTH = 2; //dips
private static final int DEFAULT_DASH_THICKNESS = 1; //dips
@ColorInt
private static final int DEFAULT_DASH_COLOR = Color.DKGRAY;
@Orientation
private int mOrientation;
private float mDashGap;
private float mDashWidth;
private float mDashThickness;
@ColorInt
private int mDashColor;
private PointF mStart;
private PointF mEnd;
private Paint mPaint;
private boolean mReadyForDrawing;
private float[] mDashIntervalsArray;
public DividerView(Context context) {
super(context);
init(context, null);
}
public DividerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public DividerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public DividerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attributeSet) {
if(isInEditMode()) {
return;
}
if(attributeSet != null) {
final TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.DividerView);
mOrientation = enumValueToOrientation(typedArray.getInt(R.styleable.DividerView_orientation, DEFAULT_ORIENTATION));
mDashGap = typedArray.getDimensionPixelSize(R.styleable.DividerView_dashGap, (int) dpToPx(DEFAULT_DASH_GAP));
mDashWidth = typedArray.getDimensionPixelSize(R.styleable.DividerView_dashWidth, (int) dpToPx(DEFAULT_DASH_WIDTH));
mDashThickness = typedArray.getDimensionPixelSize(R.styleable.DividerView_dashThickness, (int) dpToPx(DEFAULT_DASH_THICKNESS));
mDashColor = typedArray.getColor(R.styleable.DividerView_dashColor, DEFAULT_DASH_COLOR);
typedArray.recycle();
} else {
mOrientation = DEFAULT_ORIENTATION;
mDashColor = DEFAULT_DASH_COLOR;
mDashGap = dpToPx(DEFAULT_DASH_GAP);
mDashThickness = dpToPx(DEFAULT_DASH_THICKNESS);
mDashWidth = dpToPx(DEFAULT_DASH_WIDTH);
}
//Needed for dash path effect
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mStart = new PointF();
mEnd = new PointF();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(mDashColor);
mPaint.setStrokeWidth(mDashThickness);
mDashIntervalsArray = new float[2];
updateDashPathEffect();
mReadyForDrawing = false;
}
public void setOrientation(@Orientation int orientation) {
mOrientation = orientation;
updateDashStartAndEndPositions();
invalidate();
}
public void setDashGap(float dashGap) {
mDashGap = dashGap;
updateDashPathEffect();
invalidate();
}
public void setDashWidth(float dashWidth) {
mDashWidth = dashWidth;
updateDashPathEffect();
invalidate();
}
public void setDashThickness(float dashThickness) {
mDashThickness = dashThickness;
mPaint.setStrokeWidth(mDashThickness);
invalidate();
}
public void setDashColor(@ColorInt int dashColor) {
this.mDashColor = dashColor;
mPaint.setColor(mDashColor);
invalidate();
}
private void updateDashStartAndEndPositions() {
if(mReadyForDrawing) {
if(mOrientation == ORIENTATION_HORIZONTAL) {
mStart.x = 0F;
mStart.y = getHeight() * 0.5F;
mEnd.x = getWidth();
mEnd.y = getHeight() * 0.5F;
} else if(mOrientation == ORIENTATION_VERTICAL) {
mStart.x = getWidth() * 0.5F;
mStart.y = 0F;
mEnd.x = getWidth() * 0.5F;
mEnd.y = getHeight();
}
}
}
private void updateDashPathEffect() {
mDashIntervalsArray[0] = mDashWidth;
mDashIntervalsArray[1] = mDashGap;
mPaint.setPathEffect(new DashPathEffect(mDashIntervalsArray, 0F));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if(w > 0 && h > 0) {
mReadyForDrawing = true;
updateDashStartAndEndPositions();
}
}
@Orientation
private int enumValueToOrientation(int orientationValue) {
return orientationValue == 0 ? ORIENTATION_HORIZONTAL : ORIENTATION_VERTICAL;
}
/**
* Converts a raw dp value to a pixel value, based on the device density
*/
private float dpToPx(float dp) {
return dp * Resources.getSystem().getDisplayMetrics().density;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mReadyForDrawing) {
canvas.drawLine(mStart.x, mStart.y, mEnd.x, mEnd.y, mPaint);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment