Custom Android Progress Views
Repository
https://github.com/bxute/Custom-ProgressViews
Custom Android Progress Views
Motivation of building it
Android SDK is equipped with default progress bar
Sometimes we need a custom User experience with a new design and appearance behavior. There we require to write custom view from scratch.
In this project, I have tried to mock Windows Phone animation on Android platform.
Now comes the mechanics behind these.
Bubbling Progress View
Trigonometry helped a lot in achieving this.
To achieve the animation
ValueAnimatoris run from 0 to 360.- Updates are listened
- Radiuses are calculated
- Views are rendered
ValueAnimator class provides a simple timing engine for running animations which calculate animated values and set them on target objects.
We can listen to updates for intermediate angle values being animated by this class.
This returns a single value ranging from 0 to 360.
We consider this as Reference angle as you can see in the above illustration.
Each bubble is drawn in reference to the last bubble with a Phase Difference.
The phase difference is calculated by:
mPhaseDifference = 90 / (BUBBLE_COUNT - 1);
In order to draw a circle, we need its radius. In this Progress view, Max Radius of the bubble is fixed so that it can grow to that extent and then shrink down.
Now we need to calculate a radius of each circle. The radius of the circle depends on its phase difference, circle index(position of a circle from left to right) , max radius.
int radius = maxRadius * factor;
Here factor is nothing but y-intercept of the coordinate system for a given angle. Since its value range from 0 to 1, For 1 first circle we get 0 radii and for the last circle, we get the max radius.
Code for getting Factor:
private double getFactor(int animatedAngle, int circleIndex) {
return Math.abs(Math.cos(getRadian((int)(animatedAngle + (circleIndex * mPhaseDifference)))));
}
This helper method will be used for calculating radii when we get an update from ValueAnimator.
Code snippet for ValueAnimator Update:
final ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 360);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
for (int i = 0; i < BUBBLE_COUNT; i++) {
radiuses[i] = mBubbleMaxRadiusInPx * getFactor((Integer) valueAnimator.getAnimatedValue(), i);
}
invalidate();
}
});
We are storing radiuses in a array and use this array while drawing each circle at the same time.
Code snippet for drawing :
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float originX = mBubbleMaxRadiusInPx;
float originY = mBubbleMaxRadiusInPx;
for (int i = 0; i < BUBBLE_COUNT; i++) {
//draw circle
canvas.drawCircle(originX, originY, (float) radiuses[i], mPaint);
//prepare next origin info
originX += 2 * mBubbleMaxRadiusInPx + mBubbleGapInPx;
}
}
Earthworm Progress View
The name seems funny 😀. I named it earthworm because its movement behavior resembles the movement of an earthworm.
Anyway, the mechanics behind this is Bezier curve.
This animation contains 3 phase of each dots.
Deaccelerate from left -> move with constant speed-> accelerate and go off the screen to right
If we imagine the movements, then we get something like
This is a bezier curve of 3rd degree. To get this curve, we need 4 values ( startX , endX , startY , endY).
I found a very useful tool online to get these values: http://cubic-bezier.com/
Now i added Interpolator for ValueAnimator CubicBezierInterpolator.
Some lines of this interpolator:
public class CubicBezierInterpolator implements Interpolator {
public static final CubicBezierInterpolator STANDARD_CURVE = new CubicBezierInterpolator(.33, .7, .7, 0.33);
public static final CubicBezierInterpolator CURVE_TYPE_ONE = new CubicBezierInterpolator(.15,.79,.79,.15);
protected PointF start;
protected PointF end;
protected PointF a = new PointF();
protected PointF b = new PointF();
protected PointF c = new PointF();
public CubicBezierInterpolator(PointF start, PointF end) throws IllegalArgumentException {
if (start.x < 0 || start.x > 1) {
throw new IllegalArgumentException("startX value must be in the range [0, 1]");
}
if (end.x < 0 || end.x > 1) {
throw new IllegalArgumentException("endX value must be in the range [0, 1]");
}
this.start = start;
this.end = end;
}
...
...
You can mention public static final CubicBezierInterpolator STANDARD_CURVE = new CubicBezierInterpolator(.33, .7, .7, 0.33);
The values provided in the constructor of this Class are the values responsible for such a movement.
But this is for 1 dot.
For other dots following the 1st dot, we just run the same animation but with some startDelay and finally we get this result.
You can use these in your projects just by copying the class into yours.
I will soon be releasing a Gradle dependency for this Android View.
This public repository is open for contributions and i would love to hear any suggestions.
Hope you liked it 😀.
Interpolator Code: is referred from https://gist.github.com/rocboronat/0ef85535c5cd352f10fe
GitHub Account
Commit : https://github.com/bxute/Custom-ProgressViews/commit/e574a7860740e1e08c3c97083efebffabac69c5b
Thank you for your contribution. Though in the current state, there is nothing unique in this project. Also taking code from other sources is not entertained in the Utopian. Your code in CubicBezierInterpolator is taken from https://gist.github.com/rocboronat/0ef85535c5cd352f10fe.
Please try to create something unique on your own.
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]