package com.marozzi.roundbutton.animations; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.view.View; import android.view.animation.DecelerateInterpolator; public class CircularRevealAnimatedDrawable extends BaseAnimatedDrawable { private boolean mIsFilled; private Paint mPaint; private Paint mPaintImageReady; private View mAnimatedView; private float mRadius; private float mFinalRadius; private ValueAnimator mRevealInAnimation; private boolean isRunning; private float mCenterWidth; private float mCenterHeith; private Bitmap mReadyImage; private int mImageReadyAlpha; private float bitMapXOffset; private float bitMapYOffset; /** * @param view The view that if being animated * @param fillColor The color of the background that will the revealed * @param bitmap The animage that will be shown in the end of the animation. */ public CircularRevealAnimatedDrawable(View view, int fillColor, Bitmap bitmap) { mAnimatedView = view; isRunning = false; mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(fillColor); mPaintImageReady = new Paint(); mPaintImageReady.setAntiAlias(true); mPaintImageReady.setStyle(Paint.Style.FILL); mPaintImageReady.setColor(Color.TRANSPARENT); mReadyImage = bitmap; mImageReadyAlpha = 0; mRadius = 0; } public boolean isFilled() { return mIsFilled; } /** * The method is called when bounds change * * @param bounds */ @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); int bitMapWidth = (int) ((bounds.right - bounds.left) * 0.6); int bitMapHeight = (int) ((bounds.bottom - bounds.top) * 0.6); bitMapXOffset = (float) (((bounds.right - bounds.left) - bitMapWidth) / 2); bitMapYOffset = (float) (((bounds.bottom - bounds.top) - bitMapHeight) / 2); mReadyImage = Bitmap.createScaledBitmap(mReadyImage, bitMapWidth, bitMapHeight, false); mFinalRadius = (bounds.right - bounds.left) / 2; mCenterWidth = (bounds.right + bounds.left) / 2; mCenterHeith = (bounds.bottom + bounds.top) / 2; } /** * Setup all the animations. There are a reveal animation to show the button background * and a alpha animation to show the bitmap. */ @Override public void setupAnimations() { final ValueAnimator alphaAnimator = ValueAnimator.ofInt(0, 255); alphaAnimator.setDuration(100); alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mImageReadyAlpha = (int) animation.getAnimatedValue(); invalidateSelf(); mAnimatedView.invalidate(); } }); mRevealInAnimation = ValueAnimator.ofFloat(0, mFinalRadius); mRevealInAnimation.setInterpolator(new DecelerateInterpolator()); mRevealInAnimation.setDuration(120); mRevealInAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mRadius = (float) animation.getAnimatedValue(); invalidateSelf(); mAnimatedView.invalidate(); } }); mRevealInAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); mIsFilled = true; alphaAnimator.start(); } }); } /** * Starts the animation */ @Override public void start() { if (isRunning()) { return; } setupAnimations(); isRunning = true; mRevealInAnimation.start(); } /** * Stops the animation */ @Override public void stop() { if (!isRunning()) { return; } isRunning = false; mRevealInAnimation.cancel(); } /** * @return Return if its running or not. */ @Override public boolean isRunning() { return isRunning; } @Override public void draw(Canvas canvas) { canvas.drawCircle(mCenterWidth, mCenterHeith, mRadius, mPaint); if (mIsFilled) { mPaintImageReady.setAlpha(mImageReadyAlpha); canvas.drawBitmap(mReadyImage, bitMapXOffset, bitMapYOffset, mPaintImageReady); } } @Override public void setAlpha(int alpha) { } @Override public void setColorFilter(ColorFilter colorFilter) { } @Override public int getOpacity() { return PixelFormat.OPAQUE; } @Override public void dispose() { if (mRevealInAnimation != null) { mRevealInAnimation.end(); mRevealInAnimation.removeAllUpdateListeners(); mRevealInAnimation.cancel(); } mRevealInAnimation = null; } }