How to create your own progressBar in Android.

Sree Kumar A.V
4 min readDec 21, 2016

--

Android default widget will cover most of the needs, but certain times we need to create your own custom widget. You can do this by extending the View.

In the above design you can see two circular progress bar spinning in sync with each other. It’s actually two arch rotating along with changing the sweep and start angle. Lets break this into different step.When we extend a View we need to override couple of methods, I’ll go through one by one.

View Constructors

As you can see I had overridden 3 constructors

  1. DualProgressView(Context context)->Called when it is created Programatically (new DualProgressView(this))
  2. DualProgressView(Context context, AttributeSet attrs) ->Called when view in inflated via XML. param attrs which contain collection of your attributes you passed via XML.
  3. DualProgressView(Context context, AttributeSet attrs, int defStyleAttr) ->this invoked manually to apply any default style you want to apply for your widget.

You need to override only first two constructors, if you are not worried about theming your widget.One thing to remember is that, if you cascade the constructor call, you may end up in styling issues. you can read more about the constructors here.

Measuring and Layout

@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onLayout(boolean changed,int left,int top,int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}

onMeasure is the place you decide how much width and height is needed for your view. If you have multiple child inside your custom view(if you are extending a ViewGroup and building your own layout), you should measure each child width and height using below method.

measureChildWithMargins(childView, widthMeasureSpec, 0, heightMeasureSpec, 0);

After that you should call the below method with appropriate width and height considering all the child view (if present) in your CustomView.

setMeasuredDimension(mRequiredWidth, mRequiredHeight);

In our case we need a Rectangular space (width == height) so, it can be done like this, while considering the padding.

int xPad = getPaddingLeft() + getPaddingRight();
int yPad = getPaddingTop() + getPaddingBottom();
int width = getMeasuredWidth() - xPad;
int height = getMeasuredHeight() - yPad;
mSize = (width < height) ? width : height;
setMeasuredDimension(mSize + xPad, mSize + yPad);

onLayout is required when you are going to create a CustomView which also has so many child views. onLayout we set the position of each child based on the width and height calculated in the measuring pass.We don’t need to override this in our case.

Drawing

Lets do the actual work. onDraw(Canvas canvas) is the meat of our rendering code. if you are extending a View, you are responsible for drawing the View on the Screen.

As a first step, will draw rectangle like this.

that rectangle will be our viewport, DualProgressBar bound will be determined by that Rectangle. Using the same Rect as bound, we can create circle using canvas.drawArch(mRect,startAngle,SweepAngle,useCenter,paint)

  1. mRect is the Rectangle bound for the Arch
  2. startAngle determines where to start the drawing of the Arch
  3. sweepAngle determines the distance of the sweep from the start Angle.
  4. useCenter If true, include the center of the oval in the arc, and close it if it is being stroked. This will draw a wedge.
  5. paint object for drawing the arch.

Check the below example for more clarity.

startAngle = 0 degrees
sweep angle = 90 degrees

We will be using two Rect for drawing two arch one inside the other.

bad at drawing :(

Animation

Finding the ideal duration and interpolator is tough job in Animation. Here you need to change the Angle of the Arch say (0 to 360) with decelerate interpolator, which can be done with the help of Animation Framework API.

ValueAnimator frontEndExtend = ValueAnimator.ofFloat(0, 360);
frontEndExtend.setDuration(1000);
frontEndExtend.setInterpolator(new DecelerateInterpolator(1));
frontEndExtend.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
indeterminateSweep = (Float) animation.getAnimatedValue();
invalidate();
}
});

Value Animator help you to animate value and onAnimationUpdate callback,give you all the intermediate state while transition from beginning value(0) to end value (360) which can be combined with your interpolator supplied.

Animation clean up, like stopping the animation and resuming animation is done here.

@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
startAnimation();
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopAnimation();
}

If you just play around with mStartAngle and SweepAngle along with valueAnimator you can build spinning progressBar like this.

find the code below

if you can do little tweak with animation choreography and duration, can make something resemble to this.

You can checkout the complete source here (@github)

Inspired(shamelessly modified :) ) from this. ¯\_(ツ)_/¯

Thanks for reading.

--

--

Sree Kumar A.V
Sree Kumar A.V

Written by Sree Kumar A.V

Lead Android Software Engineer @ YML

Responses (5)