Back to project page Material.
The source code is released under:
Apache License
If you think the Android project Material listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.rey.material.drawable; //from ww w . j a va 2s. c om import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import com.rey.material.util.ColorUtil; import com.rey.material.util.ViewUtil; public class RevealDrawable extends Drawable implements Animatable { private boolean mRunning = false; private long mStartTime; private float mAnimProgress; private Paint mShaderPaint; private Paint mFillPaint; private int mCurColor; private RadialGradient mShader; private Matrix mMatrix; private RectF mRect; private float mMaxRadius; private ColorChangeTask[] mTasks; private int mCurTask; private boolean mCurColorTransparent; private boolean mNextColorTransparent; private static final float[] GRADIENT_STOPS = new float[]{0f, 0.99f, 1f}; private static final float GRADIENT_RADIUS = 16; public RevealDrawable(int color){ mShaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mShaderPaint.setStyle(Paint.Style.FILL); mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mFillPaint.setStyle(Paint.Style.FILL); mCurColor = color; mRect = new RectF(); mMatrix = new Matrix(); } public int getCurColor(){ return mCurColor; } public void setCurColor(int color){ if(mCurColor != color){ mCurColor = color; mCurColorTransparent = Color.alpha(mCurColor) == 0; invalidateSelf(); } } private float getMaxRadius(float x, float y, Rect bounds){ float x1 = x < bounds.centerX() ? bounds.right : bounds.left; float y1 = y < bounds.centerY() ? bounds.bottom : bounds.top; return (float)Math.sqrt(Math.pow(x1 - x, 2) + Math.pow(y1 - y, 2)); } private RadialGradient getShader(ColorChangeTask task){ if(mShader == null){ if(task.isOut){ int color_middle = ColorUtil.getColor(mCurColor, 0f); mShader = new RadialGradient(task.x, task.y, GRADIENT_RADIUS, new int[]{0, color_middle, mCurColor}, GRADIENT_STOPS, Shader.TileMode.CLAMP); } else{ int color_middle = ColorUtil.getColor(task.color, 0f); mShader = new RadialGradient(task.x, task.y, GRADIENT_RADIUS, new int[]{0, color_middle, task.color}, GRADIENT_STOPS, Shader.TileMode.CLAMP); } } return mShader; } private void fillCanvas(Canvas canvas, int color, boolean transparent){ if(transparent) return; mFillPaint.setColor(color); canvas.drawRect(getBounds(), mFillPaint); } private void fillCanvasWithHole(Canvas canvas, ColorChangeTask task, float radius, boolean transparent){ if(transparent) return; float scale = radius / GRADIENT_RADIUS; mMatrix.reset(); mMatrix.postScale(scale, scale, task.x, task.y); RadialGradient shader = getShader(task); shader.setLocalMatrix(mMatrix); mShaderPaint.setShader(shader); canvas.drawRect(getBounds(), mShaderPaint); } private void fillCircle(Canvas canvas, float x, float y, float radius, int color, boolean transparent){ if(transparent) return; mFillPaint.setColor(color); mRect.set(x - radius, y - radius, x + radius, y + radius); canvas.drawOval(mRect, mFillPaint); } @Override public void draw(Canvas canvas) { if(!isRunning()) fillCanvas(canvas, mCurColor, mCurColorTransparent); else{ ColorChangeTask task = mTasks[mCurTask]; if(mAnimProgress == 0f) fillCanvas(canvas, mCurColor, mCurColorTransparent); else if(mAnimProgress == 1f) fillCanvas(canvas, task.color, mNextColorTransparent); else if(task.isOut){ float radius = mMaxRadius * task.interpolator.getInterpolation(mAnimProgress); if(Color.alpha(task.color) == 255) fillCanvas(canvas, mCurColor, mCurColorTransparent); else fillCanvasWithHole(canvas, task, radius, mCurColorTransparent); fillCircle(canvas, task.x, task.y, radius, task.color, mNextColorTransparent); } else{ float radius = mMaxRadius * task.interpolator.getInterpolation(mAnimProgress); if(Color.alpha(mCurColor) == 255) fillCanvas(canvas, task.color, mNextColorTransparent); else fillCanvasWithHole(canvas, task, radius, mNextColorTransparent); fillCircle(canvas, task.x, task.y, radius, mCurColor, mCurColorTransparent); } } } public void changeColor(int color, int duration, Interpolator interpolator, float x, float y, boolean out){ changeColor(new ColorChangeTask(color, duration, interpolator, x, y, out)); } public void changeColor(ColorChangeTask... tasks){ for(int i = 0; i < tasks.length; i++) if(tasks[i].color != mCurColor){ mCurTask = i; mTasks = tasks; start(); break; } } @Override public void setAlpha(int alpha) { mShaderPaint.setAlpha(alpha); mFillPaint.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { mShaderPaint.setColorFilter(cf); mFillPaint.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } private void resetAnimation(){ mStartTime = SystemClock.uptimeMillis(); mAnimProgress = 0f; mCurColorTransparent = Color.alpha(mCurColor) == 0; mNextColorTransparent = Color.alpha(mTasks[mCurTask].color) == 0; mMaxRadius = getMaxRadius(mTasks[mCurTask].x, mTasks[mCurTask].y, getBounds()); mShader = null; } @Override public void start() { if(isRunning()) return; resetAnimation(); scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); invalidateSelf(); } @Override public void stop() { if(!isRunning()) return; mTasks = null; mRunning = false; unscheduleSelf(mUpdater); invalidateSelf(); } @Override public boolean isRunning() { return mRunning; } @Override public void scheduleSelf(Runnable what, long when) { mRunning = true; super.scheduleSelf(what, when); } private final Runnable mUpdater = new Runnable() { @Override public void run() { update(); } }; private void update(){ long curTime = SystemClock.uptimeMillis(); mAnimProgress = Math.min(1f, (float)(curTime - mStartTime) / mTasks[mCurTask].duration); if(mAnimProgress == 1f){ setCurColor(mTasks[mCurTask].color); for(mCurTask = mCurTask + 1; mCurTask < mTasks.length; mCurTask++) if(mTasks[mCurTask].color != mCurColor){ resetAnimation(); break; } if(mCurTask == mTasks.length) stop(); } invalidateSelf(); if(isRunning()) scheduleSelf(mUpdater, SystemClock.uptimeMillis() + ViewUtil.FRAME_DURATION); } public static class ColorChangeTask{ public final int color; public final int duration; public final Interpolator interpolator; public final float x; public final float y; public final boolean isOut; public ColorChangeTask(int color, int duration, Interpolator interpolator, float x, float y, boolean out){ this.color = color; this.duration = duration; this.interpolator = interpolator == null ? new DecelerateInterpolator() : interpolator; this.x = x; this.y = y; this.isOut = out; } } }