Skip to content

Instantly share code, notes, and snippets.

@vudunguit
Last active August 18, 2016 10:26
Show Gist options
  • Save vudunguit/50715590ca141f8b1c2060a79dde8588 to your computer and use it in GitHub Desktop.
Save vudunguit/50715590ca141f8b1c2060a79dde8588 to your computer and use it in GitHub Desktop.
ImageView support set badge drawable(gift...). I just extracted the widgets from Plaid app developed by Nick Butcher(https://github.com/nickbutcher).
<declare-styleable name="ForegroundView">
<attr name="android:foreground" />
<attr name="android:foregroundInsidePadding" />
<attr name="android:foregroundGravity" />
</declare-styleable>
<declare-styleable name="BadgedImageView">
<attr name="badgeGravity">
<!-- Push object to the top of its container, not changing its size. -->
<flag name="top" value="0x30" />
<!-- Push object to the bottom of its container, not changing its size. -->
<flag name="bottom" value="0x50" />
<!-- Push object to the left of its container, not changing its size. -->
<flag name="left" value="0x03" />
<!-- Push object to the right of its container, not changing its size. -->
<flag name="right" value="0x05" />
<!-- Push object to the beginning of its container, not changing its size. -->
<flag name="start" value="0x00800003" />
<!-- Push object to the end of its container, not changing its size. -->
<flag name="end" value="0x00800005" />
</attr>
<attr name="badgePadding" format="dimension|reference"/>
</declare-styleable>
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import io.plaidapp.R;
/**
* A view group that draws a badge drawable on top of it's contents.
*/
public class BadgedFourThreeImageView extends FourThreeImageView {
private Drawable badge;
private boolean drawBadge;
private boolean badgeBoundsSet = false;
private int badgeGravity;
private int badgePadding;
public BadgedFourThreeImageView(Context context, AttributeSet attrs) {
super(context, attrs);
badge = new GifBadge(context);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BadgedImageView, 0, 0);
badgeGravity = a.getInt(R.styleable.BadgedImageView_badgeGravity, Gravity.END | Gravity
.BOTTOM);
badgePadding = a.getDimensionPixelSize(R.styleable.BadgedImageView_badgePadding, 0);
a.recycle();
}
public void showBadge(boolean show) {
drawBadge = show;
}
public void setBadgeColor(@ColorInt int color) {
badge.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (drawBadge) {
if (!badgeBoundsSet) {
layoutBadge();
}
badge.draw(canvas);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
layoutBadge();
}
private void layoutBadge() {
Rect badgeBounds = badge.getBounds();
Gravity.apply(badgeGravity,
badge.getIntrinsicWidth(),
badge.getIntrinsicHeight(),
new Rect(0, 0, getWidth(), getHeight()),
badgePadding,
badgePadding,
badgeBounds);
badge.setBounds(badgeBounds);
badgeBoundsSet = true;
}
/**
* A drawable for indicating that an image is animated
*/
private static class GifBadge extends Drawable {
private static final String GIF = "GIF";
private static final int TEXT_SIZE = 12; // sp
private static final int PADDING = 4; // dp
private static final int CORNER_RADIUS = 2; // dp
private static final int BACKGROUND_COLOR = Color.WHITE;
private static final String TYPEFACE = "sans-serif-black";
private static final int TYPEFACE_STYLE = Typeface.NORMAL;
private static Bitmap bitmap;
private static int width;
private static int height;
private final Paint paint;
GifBadge(Context context) {
if (bitmap == null) {
final DisplayMetrics dm = context.getResources().getDisplayMetrics();
final float density = dm.density;
final float scaledDensity = dm.scaledDensity;
final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint
.SUBPIXEL_TEXT_FLAG);
textPaint.setTypeface(Typeface.create(TYPEFACE, TYPEFACE_STYLE));
textPaint.setTextSize(TEXT_SIZE * scaledDensity);
final float padding = PADDING * density;
final float cornerRadius = CORNER_RADIUS * density;
final Rect textBounds = new Rect();
textPaint.getTextBounds(GIF, 0, GIF.length(), textBounds);
height = (int) (padding + textBounds.height() + padding);
width = (int) (padding + textBounds.width() + padding);
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setHasAlpha(true);
final Canvas canvas = new Canvas(bitmap);
final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
backgroundPaint.setColor(BACKGROUND_COLOR);
canvas.drawRoundRect(0, 0, width, height, cornerRadius, cornerRadius,
backgroundPaint);
// punch out the word 'GIF', leaving transparency
textPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawText(GIF, padding, height - padding, textPaint);
}
paint = new Paint();
}
@Override
public int getIntrinsicWidth() {
return width;
}
@Override
public int getIntrinsicHeight() {
return height;
}
@Override
public void draw(Canvas canvas) {
canvas.drawBitmap(bitmap, getBounds().left, getBounds().top, paint);
}
@Override
public void setAlpha(int alpha) {
// ignored
}
@Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return 0;
}
}
}
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ViewOutlineProvider;
import android.widget.ImageView;
import io.plaidapp.R;
/**
* An extension to {@link ImageView} which has a foreground drawable.
*/
public class ForegroundImageView extends ImageView {
private Drawable foreground;
public ForegroundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundView);
final Drawable d = a.getDrawable(R.styleable.ForegroundView_android_foreground);
if (d != null) {
setForeground(d);
}
a.recycle();
setOutlineProvider(ViewOutlineProvider.BOUNDS);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (foreground != null) {
foreground.setBounds(0, 0, w, h);
}
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || (who == foreground);
}
@Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
if (foreground != null) foreground.jumpToCurrentState();
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (foreground != null && foreground.isStateful()) {
foreground.setState(getDrawableState());
}
}
/**
* Returns the drawable used as the foreground of this view. The
* foreground drawable, if non-null, is always drawn on top of the children.
*
* @return A Drawable or null if no foreground was set.
*/
public Drawable getForeground() {
return foreground;
}
/**
* Supply a Drawable that is to be rendered on top of the contents of this ImageView
*
* @param drawable The Drawable to be drawn on top of the ImageView
*/
public void setForeground(Drawable drawable) {
if (foreground != drawable) {
if (foreground != null) {
foreground.setCallback(null);
unscheduleDrawable(foreground);
}
foreground = drawable;
if (foreground != null) {
foreground.setBounds(0, 0, getWidth(), getHeight());
setWillNotDraw(false);
foreground.setCallback(this);
if (foreground.isStateful()) {
foreground.setState(getDrawableState());
}
} else {
setWillNotDraw(true);
}
invalidate();
}
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (foreground != null) {
foreground.draw(canvas);
}
}
@Override
public void drawableHotspotChanged(float x, float y) {
super.drawableHotspotChanged(x, y);
if (foreground != null) {
foreground.setHotspot(x, y);
}
}
}
import android.content.Context;
import android.util.AttributeSet;
/**
* A extension of ForegroundImageView that is always 4:3 aspect ratio.
*/
public class FourThreeImageView extends ForegroundImageView {
public FourThreeImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
int fourThreeHeight = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthSpec) * 3 / 4,
MeasureSpec.EXACTLY);
super.onMeasure(widthSpec, fourThreeHeight);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment