Skip to content

Instantly share code, notes, and snippets.

@bhurling
Last active August 29, 2015 14:00
Show Gist options
  • Save bhurling/800182623541887c66d9 to your computer and use it in GitHub Desktop.
Save bhurling/800182623541887c66d9 to your computer and use it in GitHub Desktop.
Convenience factory for creating fullscreen backgrounds that are partially transparent and may contain multiple circular punch holes to let the lower layers shine through.
package com.exmaple.overlay;
import android.app.Activity;
import android.graphics.*;
import android.graphics.drawable.BitmapDrawable;
/**
* Convenience factory for creating fullscreen backgrounds that are partially transparent and may contain
* multiple circular punch holes to let the lower layers shine through. </br></br>
*
* In your activity call
* <pre>
* BitmapDrawable background = OverlayBackground.create(this)
* .punch(radius, x, y)
* .build();
* </pre>
* This will create a BitmapDrawable that fits the current screen size. Use this drawable as background
* for a view that you add to the activity's DecorView.
*/
public class OverlayBackground {
/**
* Create a new Builder instance. Will extract all screen sizes and offsets from the given <code>activity</code>
* to create a matching drawable.
*
* @param activity the activity that wants an overlay.
* @return the builder instance to do further customizations on.
*/
public static Builder create(Activity activity) {
return new Builder(activity);
}
/**
* Internal builder class that is responsible for creating overlay backgrounds of the correct size.
*/
public static class Builder {
/**
* Reference to the activity that wants an overlay.
*/
final Activity mActivity;
/**
* Will be drawn on.
*/
Bitmap mBackground;
/**
* Will do the actual drawing.
*/
Canvas mCanvas;
/**
* An offset that respects the status bar at the top of the screen for any y-values passed
* into any draw function.
*/
int mOffsetTop;
/**
* Create a new Builder instance. Will extract all screen sizes and offsets from the given <code>activity</code>
* to create a matching drawable.
*
* @param activity the activity that wants an overlay.
*/
public Builder(Activity activity) {
mActivity = activity;
// The activity may have a status bar attached but the decor view starts at 0, 0 of the screen
// so we have to extract the offset.
Rect visibleFrame = new Rect();
mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleFrame);
mOffsetTop = visibleFrame.top;
// find out the DecorView's dimensions
int width = mActivity.getWindow().getDecorView().getWidth();
int height = mActivity.getWindow().getDecorView().getHeight();
// initialize the background and the canvas to do the actual drawing
mBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBackground);
}
/**
* set the background color of this overlay. Should be called before any call call to <code>punch</code>
* so <code>punch</code> has something to actually punch through.
*
* @param color the color for the bachground
*
* @return this Builder instance for chaining calls.
*/
public Builder color(int color) {
// Create a paint object with the given color
Paint paint = new Paint();
paint.setColor(color);
// Draw a fullscreen rectangle
mCanvas.drawRect(0, 0, mBackground.getWidth(), mBackground.getHeight(), paint);
// Return this so we can chain
return this;
}
/**
* Punches a transparent, circular hole through the otherwise semi-transparent drawable.
*
* @param radius the radius for the hole (in dips)
* @param x x location on the screen (in dips)
* @param y y location on the screen (in dips). Respects the status bar if there is any.
*
* @return this Builder instance for chaining calls.
*/
public Builder punch(float radius, float x, float y) {
// Create a paint object that wipes out pixels
Paint rubber = new Paint();
rubber.setAntiAlias(true);
rubber.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
// Wipe out a circle. This will convert the given values from dips to pixels
// and also respects the offset given by the status bar.
mCanvas.drawCircle(dipToPx(x), dipToPx(y) + mOffsetTop, dipToPx(radius), rubber);
return this;
}
/**
* Actually create the previously configured overlay background.
*
* @return a drawable that can be used as background for views added to the activity's DecorView
*/
public BitmapDrawable build() {
return new BitmapDrawable(mActivity.getResources(), mBackground);
}
/**
* Private helper to convert dips in on-screen pixels
*/
private float dipToPx(float dip) {
return mActivity.getResources().getDisplayMetrics().density * dip;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment