SwipeProgressBarpublic final class SwipeProgressBar extends Object Custom progress bar that shows a cycle of colors as widening circles that
overdraw each other. When finished, the bar is cleared from the inside out as
the main cycle continues. Before running, this can also indicate how close
the user is to triggering something (e.g. how far they need to pull down to
trigger a refresh). |
Fields Summary |
---|
private static final int | COLOR1 | private static final int | COLOR2 | private static final int | COLOR3 | private static final int | COLOR4 | private static final int | ANIMATION_DURATION_MS | private static final int | FINISH_ANIMATION_DURATION_MS | private static final android.view.animation.Interpolator | INTERPOLATOR | private final android.graphics.Paint | mPaint | private final android.graphics.RectF | mClipRect | private float | mTriggerPercentage | private long | mStartTime | private long | mFinishTime | private boolean | mRunning | private int | mColor1 | private int | mColor2 | private int | mColor3 | private int | mColor4 | private android.view.View | mParent | private android.graphics.Rect | mBounds |
Constructors Summary |
---|
public SwipeProgressBar(android.view.View parent)
mParent = parent;
mColor1 = COLOR1;
mColor2 = COLOR2;
mColor3 = COLOR3;
mColor4 = COLOR4;
|
Methods Summary |
---|
void | draw(android.graphics.Canvas canvas)
final int width = mBounds.width();
final int height = mBounds.height();
final int cx = width / 2;
final int cy = height / 2;
boolean drawTriggerWhileFinishing = false;
int restoreCount = canvas.save();
canvas.clipRect(mBounds);
if (mRunning || (mFinishTime > 0)) {
long now = AnimationUtils.currentAnimationTimeMillis();
long elapsed = (now - mStartTime) % ANIMATION_DURATION_MS;
long iterations = (now - mStartTime) / ANIMATION_DURATION_MS;
float rawProgress = (elapsed / (ANIMATION_DURATION_MS / 100f));
// If we're not running anymore, that means we're running through
// the finish animation.
if (!mRunning) {
// If the finish animation is done, don't draw anything, and
// don't repost.
if ((now - mFinishTime) >= FINISH_ANIMATION_DURATION_MS) {
mFinishTime = 0;
return;
}
// Otherwise, use a 0 opacity alpha layer to clear the animation
// from the inside out. This layer will prevent the circles from
// drawing within its bounds.
long finishElapsed = (now - mFinishTime) % FINISH_ANIMATION_DURATION_MS;
float finishProgress = (finishElapsed / (FINISH_ANIMATION_DURATION_MS / 100f));
float pct = (finishProgress / 100f);
// Radius of the circle is half of the screen.
float clearRadius = width / 2 * INTERPOLATOR.getInterpolation(pct);
mClipRect.set(cx - clearRadius, 0, cx + clearRadius, height);
canvas.saveLayerAlpha(mClipRect, 0, 0);
// Only draw the trigger if there is a space in the center of
// this refreshing view that needs to be filled in by the
// trigger. If the progress view is just still animating, let it
// continue animating.
drawTriggerWhileFinishing = true;
}
// First fill in with the last color that would have finished drawing.
if (iterations == 0) {
canvas.drawColor(mColor1);
} else {
if (rawProgress >= 0 && rawProgress < 25) {
canvas.drawColor(mColor4);
} else if (rawProgress >= 25 && rawProgress < 50) {
canvas.drawColor(mColor1);
} else if (rawProgress >= 50 && rawProgress < 75) {
canvas.drawColor(mColor2);
} else {
canvas.drawColor(mColor3);
}
}
// Then draw up to 4 overlapping concentric circles of varying radii, based on how far
// along we are in the cycle.
// progress 0-50 draw mColor2
// progress 25-75 draw mColor3
// progress 50-100 draw mColor4
// progress 75 (wrap to 25) draw mColor1
if ((rawProgress >= 0 && rawProgress <= 25)) {
float pct = (((rawProgress + 25) * 2) / 100f);
drawCircle(canvas, cx, cy, mColor1, pct);
}
if (rawProgress >= 0 && rawProgress <= 50) {
float pct = ((rawProgress * 2) / 100f);
drawCircle(canvas, cx, cy, mColor2, pct);
}
if (rawProgress >= 25 && rawProgress <= 75) {
float pct = (((rawProgress - 25) * 2) / 100f);
drawCircle(canvas, cx, cy, mColor3, pct);
}
if (rawProgress >= 50 && rawProgress <= 100) {
float pct = (((rawProgress - 50) * 2) / 100f);
drawCircle(canvas, cx, cy, mColor4, pct);
}
if ((rawProgress >= 75 && rawProgress <= 100)) {
float pct = (((rawProgress - 75) * 2) / 100f);
drawCircle(canvas, cx, cy, mColor1, pct);
}
if (mTriggerPercentage > 0 && drawTriggerWhileFinishing) {
// There is some portion of trigger to draw. Restore the canvas,
// then draw the trigger. Otherwise, the trigger does not appear
// until after the bar has finished animating and appears to
// just jump in at a larger width than expected.
canvas.restoreToCount(restoreCount);
restoreCount = canvas.save();
canvas.clipRect(mBounds);
drawTrigger(canvas, cx, cy);
}
// Keep running until we finish out the last cycle.
ViewCompat.postInvalidateOnAnimation(
mParent, mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
} else {
// Otherwise if we're in the middle of a trigger, draw that.
if (mTriggerPercentage > 0 && mTriggerPercentage <= 1.0) {
drawTrigger(canvas, cx, cy);
}
}
canvas.restoreToCount(restoreCount);
| private void | drawCircle(android.graphics.Canvas canvas, float cx, float cy, int color, float pct)Draws a circle centered in the view.
mPaint.setColor(color);
canvas.save();
canvas.translate(cx, cy);
float radiusScale = INTERPOLATOR.getInterpolation(pct);
canvas.scale(radiusScale, radiusScale);
canvas.drawCircle(0, 0, cx, mPaint);
canvas.restore();
| private void | drawTrigger(android.graphics.Canvas canvas, int cx, int cy)
mPaint.setColor(mColor1);
canvas.drawCircle(cx, cy, cx * mTriggerPercentage, mPaint);
| boolean | isRunning()
return mRunning || mFinishTime > 0;
| void | setBounds(int left, int top, int right, int bottom)Set the drawing bounds of this SwipeProgressBar.
mBounds.left = left;
mBounds.top = top;
mBounds.right = right;
mBounds.bottom = bottom;
| void | setColorScheme(int color1, int color2, int color3, int color4)Set the four colors used in the progress animation. The first color will
also be the color of the bar that grows in response to a user swipe
gesture.
mColor1 = color1;
mColor2 = color2;
mColor3 = color3;
mColor4 = color4;
| void | setTriggerPercentage(float triggerPercentage)Update the progress the user has made toward triggering the swipe
gesture. and use this value to update the percentage of the trigger that
is shown.
mTriggerPercentage = triggerPercentage;
mStartTime = 0;
ViewCompat.postInvalidateOnAnimation(
mParent, mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
| void | start()Start showing the progress animation.
if (!mRunning) {
mTriggerPercentage = 0;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mRunning = true;
mParent.postInvalidate();
}
| void | stop()Stop showing the progress animation.
if (mRunning) {
mTriggerPercentage = 0;
mFinishTime = AnimationUtils.currentAnimationTimeMillis();
mRunning = false;
mParent.postInvalidate();
}
|
|