Last active
January 1, 2019 19:50
-
-
Save fdoyle/8117037 to your computer and use it in GitHub Desktop.
SupernovaView, as demonstrated by the LG G2 lock screen where you click and drag to "punch a hole" through the lock screen to the home screen. This view extends ImageView to the same effect.Probably not as optimized as it could be, but it seems about as smooth as LGs implementation.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lacronicus.supernova; | |
import android.animation.ValueAnimator; | |
import android.content.Context; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapFactory; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.graphics.PorterDuff; | |
import android.graphics.PorterDuffXfermode; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.widget.ImageView; | |
/** | |
* Created by fdoyle on 12/24/13. | |
*/ | |
public class SupernovaView extends ImageView { | |
float minRadius = 100; | |
float unlockRadius = 400; | |
public SupernovaView(Context context) { | |
super(context); | |
setup(); | |
} | |
public SupernovaView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
setup(); | |
} | |
public SupernovaView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
setup(); | |
} | |
float startX = 0; | |
float startY = 0; | |
float radius = 0; | |
private void setup() { | |
setOnTouchListener(new OnTouchListener() { | |
@Override | |
public boolean onTouch(View v, MotionEvent event) { | |
switch (event.getAction()) { | |
case MotionEvent.ACTION_DOWN: | |
startX = event.getX(); | |
startY = event.getY(); | |
break; | |
case MotionEvent.ACTION_MOVE: | |
SupernovaView.this.postInvalidate(); | |
double x = event.getX(); | |
double y = event.getY(); | |
radius = (float) Math.sqrt( (startX -x) * (startX - x) + (startY - y) * (startY -y)); | |
if(radius < minRadius) { | |
radius = minRadius; | |
} | |
break; | |
case MotionEvent.ACTION_UP: | |
final float currentRadius = radius; | |
if(radius > unlockRadius) { | |
float maxRadius = (float) Math.sqrt(getWidth() * getWidth() + getHeight() * getHeight()); | |
ValueAnimator valueAnimator = ValueAnimator.ofFloat(currentRadius, maxRadius); | |
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | |
@Override | |
public void onAnimationUpdate(ValueAnimator animation) { | |
setRadius((Float) animation.getAnimatedValue()); | |
} | |
}); | |
valueAnimator.setDuration(360); | |
valueAnimator.start(); | |
} else { | |
ValueAnimator valueAnimator = ValueAnimator.ofFloat(currentRadius, 0); | |
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | |
@Override | |
public void onAnimationUpdate(ValueAnimator animation) { | |
setRadius((Float) animation.getAnimatedValue()); | |
} | |
}); | |
valueAnimator.setDuration(360); | |
valueAnimator.start(); | |
} | |
break; | |
} | |
return true; | |
} | |
}); | |
} | |
public void setRadius(float radius) { | |
this.radius = radius; | |
postInvalidate(); | |
} | |
Bitmap b; | |
Canvas maskCanvas; | |
@Override | |
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { | |
super.onLayout(changed, left, top, right, bottom); | |
if(changed) { | |
b = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888); | |
maskCanvas = new Canvas(b); | |
} | |
} | |
Paint clearPaint = new Paint(); | |
Paint atopPaint = new Paint(); | |
Paint imagePaint = new Paint(); | |
PorterDuffXfermode src_atop = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP); | |
PorterDuffXfermode overlay = new PorterDuffXfermode(PorterDuff.Mode.OVERLAY); | |
PorterDuffXfermode clear = new PorterDuffXfermode(PorterDuff.Mode.CLEAR); | |
@Override | |
protected void onDraw(Canvas canvas) { | |
clearPaint.setXfermode(clear); | |
atopPaint.setXfermode(src_atop); | |
imagePaint.setXfermode(overlay); | |
super.onDraw(maskCanvas); //draw this imageview to an off-screen buffer | |
maskCanvas.drawCircle(startX, startY, radius, clearPaint); // make part of that buffer transparent | |
canvas.drawBitmap(b, 0,0, atopPaint); // draw that buffer to the canvas | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment