FileDocCategorySizeDatePackage
SwipeProgressBar.javaAPI DocAndroid 5.1 API10582Thu Mar 12 22:22:56 GMT 2015android.support.v4.widget

SwipeProgressBar

public 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
voiddraw(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 voiddrawCircle(android.graphics.Canvas canvas, float cx, float cy, int color, float pct)
Draws a circle centered in the view.

param
canvas the canvas to draw on
param
cx the center x coordinate
param
cy the center y coordinate
param
color the color to draw
param
pct the percentage of the view that the circle should cover

        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 voiddrawTrigger(android.graphics.Canvas canvas, int cx, int cy)

        mPaint.setColor(mColor1);
        canvas.drawCircle(cx, cy, cx * mTriggerPercentage, mPaint);
    
booleanisRunning()

return
Return whether the progress animation is currently running.

        return mRunning || mFinishTime > 0;
    
voidsetBounds(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;
    
voidsetColorScheme(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.

param
color1 Integer representation of a color.
param
color2 Integer representation of a color.
param
color3 Integer representation of a color.
param
color4 Integer representation of a color.

        mColor1 = color1;
        mColor2 = color2;
        mColor3 = color3;
        mColor4 = color4;
    
voidsetTriggerPercentage(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);
    
voidstart()
Start showing the progress animation.

        if (!mRunning) {
            mTriggerPercentage = 0;
            mStartTime = AnimationUtils.currentAnimationTimeMillis();
            mRunning = true;
            mParent.postInvalidate();
        }
    
voidstop()
Stop showing the progress animation.

        if (mRunning) {
            mTriggerPercentage = 0;
            mFinishTime = AnimationUtils.currentAnimationTimeMillis();
            mRunning = false;
            mParent.postInvalidate();
        }