Skip to content

Instantly share code, notes, and snippets.

@hrules6872
Last active February 1, 2016 21:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrules6872/cadbd4094d35ee541e5a to your computer and use it in GitHub Desktop.
Save hrules6872/cadbd4094d35ee541e5a to your computer and use it in GitHub Desktop.
Improved DisplayLeakConnectorView extracted from LeakCanary library
public class DisplayLeakConnectorView extends View {
private static final float DEFAULT_STROKEWIDTH = 4f;
private static final int DEFAULT_COLOR_BRANCH = 0xFFbababa;
private static final int DEFAULT_COLOR_ROOT = 0xFF84a6c5;
private static final int DEFAULT_COLOR_LEAK = 0xFFb1554e;
public static final int TYPE_START = -1;
public static final int TYPE_NODE = 0;
public static final int TYPE_END = 1;
public static final int TYPE_DEFAULT = TYPE_NODE;
@Retention(RetentionPolicy.SOURCE) @IntDef({ TYPE_START, TYPE_NODE, TYPE_END })
public @interface DisplayLeakConnectorViewType {
}
private Paint paintBranch;
private Paint paintRoot;
private Paint paintLeak;
private Paint paintClear;
private int type;
private float strokeSize;
private Bitmap cache;
public DisplayLeakConnectorView(Context context) {
this(context, null);
}
public DisplayLeakConnectorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DisplayLeakConnectorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public DisplayLeakConnectorView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
strokeSize = dpToPixel(DEFAULT_STROKEWIDTH, getResources());
type = getConnectorViewType(TYPE_DEFAULT);
paintBranch = new Paint(Paint.ANTI_ALIAS_FLAG);
paintBranch.setColor(DEFAULT_COLOR_BRANCH);
paintBranch.setStrokeWidth(strokeSize);
paintRoot = new Paint(Paint.ANTI_ALIAS_FLAG);
paintRoot.setColor(DEFAULT_COLOR_ROOT);
paintRoot.setStrokeWidth(strokeSize);
paintLeak = new Paint(Paint.ANTI_ALIAS_FLAG);
paintLeak.setColor(DEFAULT_COLOR_LEAK);
paintClear = new Paint(Paint.ANTI_ALIAS_FLAG);
paintClear.setColor(Color.TRANSPARENT);
paintClear.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
private @DisplayLeakConnectorViewType int getConnectorViewType(int value) {
return value;
}
public @DisplayLeakConnectorViewType int getType() {
return type;
}
public void setType(@DisplayLeakConnectorViewType int type) {
if (type != this.type) {
this.type = type;
invalidate();
}
}
public float getStrokeSize() {
return paintRoot.getStrokeWidth();
}
public void setStrokeSize(float strokeSize) {
paintRoot.setStrokeWidth(strokeSize);
invalidate();
}
public int getRootColor() {
return paintRoot.getColor();
}
public void setRootColor(@ColorInt int rootColor) {
paintRoot.setColor(rootColor);
invalidate();
}
public int getBranchColor() {
return paintBranch.getColor();
}
public void setBranchColor(@ColorInt int branchColor) {
paintBranch.setColor(branchColor);
invalidate();
}
public int getLeakColor() {
return paintLeak.getColor();
}
public void setLeakColor(@ColorInt int leakColor) {
paintLeak.setColor(leakColor);
invalidate();
}
@Override protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
if (cache != null && (cache.getWidth() != width || cache.getHeight() != height)) {
cache.recycle();
cache = null;
}
if (cache == null) {
cache = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas cacheCanvas = new Canvas(cache);
float halfWidth = width / 2f;
float halfHeight = height / 2f;
float thirdWidth = width / 3f;
switch (type) {
case TYPE_START:
float radiusClear = halfWidth - strokeSize / 2f;
cacheCanvas.drawRect(0, 0, width, radiusClear, paintRoot);
cacheCanvas.drawCircle(0, radiusClear, radiusClear, paintClear);
cacheCanvas.drawCircle(width, radiusClear, radiusClear, paintClear);
cacheCanvas.drawLine(halfWidth, 0, halfWidth, halfHeight, paintRoot);
cacheCanvas.drawLine(halfWidth, halfHeight, halfWidth, height, paintBranch);
cacheCanvas.drawCircle(halfWidth, halfHeight, halfWidth, paintBranch);
cacheCanvas.drawCircle(halfWidth, halfHeight, thirdWidth, paintClear);
break;
case TYPE_NODE:
cacheCanvas.drawLine(halfWidth, 0, halfWidth, height, paintBranch);
cacheCanvas.drawCircle(halfWidth, halfHeight, halfWidth, paintBranch);
cacheCanvas.drawCircle(halfWidth, halfHeight, thirdWidth, paintClear);
break;
default:
cacheCanvas.drawLine(halfWidth, 0, halfWidth, halfHeight, paintBranch);
cacheCanvas.drawCircle(halfWidth, halfHeight, thirdWidth, paintLeak);
break;
}
}
canvas.drawBitmap(cache, 0, 0, null);
}
@Override public void invalidate() {
if (cache != null) {
cache.recycle();
cache = null;
}
super.invalidate();
}
private float dpToPixel(float dp, Resources resources) {
DisplayMetrics metrics = resources.getDisplayMetrics();
return metrics.density * dp;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment