Skip to content

Instantly share code, notes, and snippets.

@muthuraj57
Last active December 14, 2020 07:16
Show Gist options
  • Save muthuraj57/c265f8d6ee50af50686571b905eb047a to your computer and use it in GitHub Desktop.
Save muthuraj57/c265f8d6ee50af50686571b905eb047a to your computer and use it in GitHub Desktop.
public class AvatarView extends AppCompatImageView {
/*
* Path of them image to be clipped (to be shown)
* */
Path clipPath;
/*
* Place holder drawable (with background color and initials)
* */
Drawable drawable;
/*
* Contains initials of the member
* */
String text;
/*
* Used to set size and color of the member initials
* */
TextPaint textPaint;
/*
* Used as background of the initials with user specific color
* */
Paint paint;
/*
* To draw border
*/
private Paint borderPaint;
/*
* Shape to be drawn
* */
int shape;
/*
* Constants to define shape
* */
protected static final int CIRCLE = 0;
protected static final int RECTANGLE = 1;
/*
* User whose avatar should be displayed
* */
User user;
/*
* Image width and height (both are same and constant, defined in dimens.xml
* We cache them in this field
* */
private int imageSize;
/*
* We will set it as 2dp
* */
int cornerRadius;
/*
* Bounds of the canvas in float
* Used to set bounds of member initial and background
* */
RectF rectF;
public AvatarView(Context context) {
super(context);
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
getAttributes(attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getAttributes(attrs);
init();
}
private void getAttributes(AttributeSet attrs) {
TypedArray a = getContext().getTheme().obtainStyledAttributes(
attrs,
R.styleable.AvatarView,
0, 0);
try {
/*
* Get the shape and set shape field accordingly
* */
String avatarShape = a.getString(R.styleable.AvatarView_avatar_shape);
/*
* If the attribute is not specified, consider circle shape
* */
if (avatarShape == null) {
shape = CIRCLE;
} else {
if (getContext().getString(R.string.rectangle).equals(avatarShape)) {
shape = RECTANGLE;
} else {
shape = CIRCLE;
}
}
} finally {
a.recycle();
}
}
/*
* Initialize fields
* */
protected void init() {
/*
* Below Jelly Bean, clipPath on canvas would not work because lack of hardware acceleration
* support. Hence, we should explicitly say to use software acceleration.
* */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
rectF = new RectF();
clipPath = new Path();
imageSize = getResources().getDimensionPixelSize(R.dimen.avatar_size);
cornerRadius = (int) Utils.dpToPixel(2, getResources());
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(16f * getResources().getDisplayMetrics().scaledDensity);
textPaint.setColor(Color.WHITE);
borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
borderPaint.setColor(ContextCompat.getColor(context, R.color.border_color));
borderPaint.setStrokeWidth(context.getResources().getDimension(R.dimen.border_width));
}
/*
* Get User object and set values based on the user
* This is the only exposed method to the developer
* */
public void setUser(User user) {
this.user = user;
setValues();
}
/*
* Set user specific fields in here
* */
private void setValues() {
/*
* user specific color for initial background
* */
paint.setColor(user.getColor());
/*
* Initials of member
* */
text = Helper.getShortName(user.getName());
setDrawable();
if (user.getAvatarUrl() != null) {
Glide.with(getContext())
.load(user.getAvatarUrl())
.placeholder(drawable)
.centerCrop()
.override(imageSize, imageSize)
.into(this);
} else {
setImageDrawable(drawable);
invalidate();
}
}
/*
* Create placeholder drawable
* */
private void setDrawable() {
drawable = new Drawable() {
@Override
public void draw(@NonNull Canvas canvas) {
int centerX = Math.round(canvas.getWidth() * 0.5f);
int centerY = Math.round(canvas.getHeight() * 0.5f);
/*
* To draw text
* */
if (text != null) {
float textWidth = textPaint.measureText(text) * 0.5f;
float textBaseLineHeight = textPaint.getFontMetrics().ascent * -0.4f;
/*
* Draw the background color before drawing initials text
* */
if (shape == RECTANGLE) {
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
} else {
canvas.drawCircle(centerX,
centerY,
Math.max(canvas.getHeight() / 2, textWidth / 2),
paint);
}
/*
* Draw the text above the background color
* */
canvas.drawText(text, centerX - textWidth, centerY + textBaseLineHeight, textPaint);
}
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
};
}
/*
* Set the canvas bounds here
* */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int screenWidth = MeasureSpec.getSize(widthMeasureSpec);
int screenHeight = MeasureSpec.getSize(heightMeasureSpec);
rectF.set(0, 0, screenWidth, screenHeight);
}
@Override
protected void onDraw(Canvas canvas) {
if (shape == RECTANGLE) {
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, borderPaint);
clipPath.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW);
} else {
canvas.drawCircle(rectF.centerX(), rectF.centerY(), (rectF.height() / 2) - borderWidth, borderPaint);
clipPath.addCircle(rectF.centerX(), rectF.centerY(), (rectF.height() / 2), Path.Direction.CW);
}
canvas.clipPath(clipPath);
super.onDraw(canvas);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment