Skip to content

Instantly share code, notes, and snippets.

@alphamu
Last active February 3, 2023 18:54
Show Gist options
  • Select an option

  • Save alphamu/cd54e60c55da91578ea2 to your computer and use it in GitHub Desktop.

Select an option

Save alphamu/cd54e60c55da91578ea2 to your computer and use it in GitHub Desktop.
Demonstration of how to make a custom TextView which has a separator running across it. Screenshot of TextView https://raw.githubusercontent.com/alphamu/RxAndroidDemo/master/app/SeparatorTextViewSample.png
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SeparatorTextViewFull">
<attr name="dividerResId" format="reference"/>
<attr name="dividerColor" format="color"/>
<attr name="dividerHeight" format="dimension"/>
<attr name="dividerTextPadding" format="dimension"/>
</declare-styleable>
</resources>
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.TextView;
/**
* Simple version used in the article:
* https://medium.com/@ali.muzaffar/creating-a-custom-textview-as-a-section-header-73cb8e194917
*/
public class SeparatorTextView extends TextView {
public SeparatorTextView(Context context) {
super(context);
}
public SeparatorTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SeparatorTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SeparatorTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// we use the default paint,
// our line will be the same color as the text.
Paint paint = getPaint();
//start at the vertical center of the textview
int top = (getHeight() + getPaddingTop() - getPaddingBottom())/2;
//start at the left margin
int left = getPaddingLeft();
//we draw all the way to the right
int right = getWidth() - getPaddingRight();
//we want the line to be 2 pixel thick
int bottom = top + 2;
int horizontalCenter = (getWidth() + getPaddingLeft() - getPaddingRight()) / 2;
int textWidth = (int) paint.measureText(getText().toString());
int halfTextWidth = textWidth/2;
int padding = 16;
int gravity = getGravity();
if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
canvas.drawRect(left + textWidth + padding, //left
top,
right,
bottom,
paint);
} else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
canvas.drawRect(left,
top,
right - textWidth - padding, //right
bottom,
paint);
} else {
canvas.drawRect(left,
top,
horizontalCenter - halfTextWidth - padding, //right
bottom,
paint);
canvas.drawRect(horizontalCenter + halfTextWidth + padding, //left
top,
right,
bottom,
paint);
}
}
}
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.widget.TextView;
/**
* use along with attrs.xml
* dividerResId will be used if provided
* dividerHeight, dividerColor are only used if dividerResId is not provided.
* dividerTextPadding is the space between the lines and the text.
*/
public class SeparatorTextViewFull extends TextView {
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Drawable mDivider;
private Paint mDividerPaint;
int mPadding = 16;
int mDividerColor = -1;
int mDividerHeight = 2;
boolean isNinePatch = false;
public SeparatorTextViewFull(Context context) {
super(context);
init(context, null);
}
public SeparatorTextViewFull(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public SeparatorTextViewFull(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SeparatorTextViewFull(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@Override
protected void onDraw(Canvas c) {
super.onDraw(c);
int left = getPaddingLeft();
int top = getPaddingTop();
int bottom = getHeight() - getPaddingBottom();
if (isNinePatch || mDivider == null) {
top = (getHeight() + getPaddingTop()) / 2;
if (mDivider != null) {
bottom = top + mDivider.getIntrinsicHeight();
} else {
bottom = top + mDividerHeight;
if (mDividerHeight > 1) {
bottom -= mDividerHeight / 2;
top -= mDividerHeight / 2;
}
}
}
int right = getWidth() - getPaddingRight();
int textWidth = (int) getTextSize();
int gravity = getGravity();
if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
if (mDivider != null) {
mDivider.setBounds(left + textWidth + mPadding, top, right, bottom);
mDivider.draw(c);
} else {
c.drawRect(left + textWidth + mPadding, top, right, bottom, mDividerPaint);
}
} else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
if (mDivider != null) {
mDivider.setBounds(left, top, right - textWidth - mPadding, bottom);
mDivider.draw(c);
} else {
c.drawRect(left, top, right - textWidth - mPadding, bottom, mDividerPaint);
}
} else {
// int w = c.getWidth();
int w = getWidth() - getPaddingLeft() - getPaddingRight();
int xPos = (w / 2) - textWidth / 2;
if (mDivider != null) {
mDivider.setBounds(left, top, xPos - mPadding, bottom);
mDivider.draw(c);
mDivider.setBounds(xPos + textWidth + mPadding, top, right, bottom);
mDivider.draw(c);
} else {
c.drawRect(left, top, xPos - mPadding, bottom, mDividerPaint);
c.drawRect(xPos + textWidth + mPadding, top, right, bottom, mDividerPaint);
}
}
}
private void init(Context context, AttributeSet attrs) {
mDividerPaint = new Paint();
mDividerPaint.setColor(getPaint().getColor());
if (attrs == null) {
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
mDivider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
} else {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SeparatorTextViewFull, 0, 0);
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SeparatorTextViewFull_dividerResId:
int dividerResId = a.getResourceId(attr, 0);
if (dividerResId != 0) {
mDivider = context.getResources().getDrawable(dividerResId);
isNinePatch = mDivider instanceof NinePatchDrawable;
} else {
mDivider = null;
}
break;
case R.styleable.SeparatorTextViewFull_dividerTextPadding:
int textPadding = a.getDimensionPixelSize(attr, mPadding);
if (textPadding != mPadding) {
mPadding = textPadding;
}
break;
case R.styleable.SeparatorTextViewFull_dividerHeight:
int dividerHeight = a.getDimensionPixelSize(attr, -1);
if (dividerHeight != -1) {
mDividerHeight = dividerHeight;
} else {
mDividerHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mDividerHeight, getResources().getDisplayMetrics());
}
break;
case R.styleable.SeparatorTextViewFull_dividerColor:
ColorStateList dividerColor = a.getColorStateList(attr);
if (dividerColor != null) {
mDividerColor = dividerColor.getColorForState(getDrawableState(), getPaint().getColor());
mDividerPaint.setColor(mDividerColor);
}
break;
}
}
a.recycle();
}
}
}
@imamsan
Copy link
Copy Markdown

imamsan commented Nov 6, 2019

Thank you. Helpfull tutorial

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment