Saturday 2 August 2014

Circular Progressbar in Android


Customize the Progressbar for better user experience.


Download Source Code Download 

Project Hierarchy
1.0 Firstly we will create a ProgressIndicator.java class which will extends View class. This class is used for showing Progressbar.
package com.tutorialsface.circularprogress;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.view.View;

/**
 * Class used to show a determinate progress indicator.
 * Two display modes are supported "wheel" and "pie"
 */
class ProgressIndicator extends View {
    private final RectF mRect = new RectF();
    private final RectF mRectInner = new RectF();
    private final Paint mPaintForeground = new Paint();
    private final Paint mPaintBackground = new Paint();
    private final Paint mPaintErase = new Paint();
    private static final Xfermode PORTER_DUFF_CLEAR = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
    private int mColorForeground = Color.WHITE;
    private int mColorBackground = Color.BLACK;
    private float mValue;
    private boolean mPieStyle;
    /**
     * Value which makes our custom drawn indicator have roughly the same size
     * as the built-in ProgressBar indicator. Unit: dp
     */
    private static final float PADDING = 4;
    private float mPadding;
    private Bitmap mBitmap;
    /**
     * Value which makes our custom drawn indicator have roughly the same
     * thickness as the built-in ProgressBar indicator. Expressed as the ration
     * between the inner and outer radiuses
     */
    private static final float INNER_RADIUS_RATIO = 0.84f;

    public ProgressIndicator(Context context) {
        this(context, null);
    }

    public ProgressIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        Resources r = context.getResources();
        float scale = r.getDisplayMetrics().density;
        mPadding = scale * PADDING ;
        mPaintForeground.setColor(mColorForeground);
        mPaintForeground.setAntiAlias(true);
        mPaintBackground.setColor(mColorBackground);
        mPaintBackground.setAntiAlias(true);
        mPaintErase.setXfermode(PORTER_DUFF_CLEAR);
        mPaintErase.setAntiAlias(true);
    }

    /**
     * Set the style of this indicator.The two supported styles are "wheel" and "pie"
     * @param style One of {@link STYLE_WHEEL} or {@link STYLE_PIE}
     */
    public void setPieStyle(boolean pieStyle) {
        if (mPieStyle == pieStyle) {
            return;
        }
        mPieStyle = pieStyle;
        updateBitmap();
    }

    /**
     * Return the current style of this indicator.
     * @return <tt>True</tt> if the indicator has the "pie" style
     */
    public boolean getIsPieStyle() {
        return mPieStyle;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmap, getWidth() / 2 - mBitmap.getWidth() / 2,
                          getHeight() / 2 - mBitmap.getHeight() / 2, null);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        float bitmapWidth = w - 2 * mPadding;
        float bitmapHeight = h - 2 * mPadding;
        float radius = Math.min(bitmapWidth / 2, bitmapHeight / 2);
        mRect.set(0, 0, bitmapWidth, bitmapHeight);
        radius *= INNER_RADIUS_RATIO;
        mRectInner.set(bitmapWidth / 2f - radius, bitmapHeight / 2f - radius, bitmapWidth / 2f + radius, bitmapHeight / 2f + radius);
        updateBitmap();
    }

    /**
     * Set the foreground color for this indicator. The foreground is the part
     * of the indicator that shows the actual progress
     */
    public void setForegroundColor(int color) {
        this.mColorForeground = color;
        mPaintForeground.setColor(color);
        invalidate();
    }
   
    /**
     * Set the background color for this indicator. The background is a dim and subtle
     * part of the indicator that appears below the actual progress
     */
    public void setBackgroundColor(int color) {
        this.mColorBackground = color;
        mPaintBackground.setColor(color);
        invalidate();
    }

    /**
     * @param value A number between 0 and 1
     */
    public synchronized void setValue(float value) {
        mValue = value;
        updateBitmap();
    }

    private void updateBitmap() {
        if (mRect == null || mRect.width() == 0) {
            return;
        }
        mBitmap = Bitmap.createBitmap((int) mRect.width(), (int) mRect.height(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(mBitmap);
        canvas.drawArc(mRect, -90, 360, true, mPaintBackground);
        if (mValue < 0.01f) {
            canvas.drawLine(mRect.width() / 2, mRect.height() / 2, mRect.width() / 2, 0, mPaintForeground);
        }
        float angle = mValue * 360;
        canvas.drawArc(mRect, -90, angle, true, mPaintForeground);
        if (!mPieStyle) {
            canvas.drawArc(mRectInner, -90, 360, true, mPaintErase);
        }
        postInvalidate();
    }
}

1.1 Call this in your xml file as-
<com.tutorialsface.circularprogress.ProgressIndicator
    android:id="@+id/determinate_progress_indicator1"
    android:layout_width="100dp"
    android:layout_height="100dp" />

1.2 For setting the background and foreground color of progressbar use-
mProgressIndicator1.setForegroundColor(Color.parseColor("#b0120a"));

mProgressIndicator1.setBackgroundColor(Color.parseColor("#f69988"));

1.3 If you want Pie style progressbar use-
mProgressIndicator1.setPieStyle(true);

1.4 To show Progress use (Value between 0-1)-
mProgressIndicator1.setValue(0.5);

2.0 Now for demo open activity_main.xml and write down following code.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btnreset"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Restart" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal" >

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator1"
                android:layout_width="100dp"
                android:layout_height="100dp" />

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator2"
                android:layout_width="100dp"
                android:layout_height="100dp" />

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator3"
                android:layout_width="100dp"
                android:layout_height="100dp" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal" >

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator4"
                android:layout_width="100dp"
                android:layout_height="100dp" />

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator5"
                android:layout_width="100dp"
                android:layout_height="100dp" />

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator6"
                android:layout_width="100dp"
                android:layout_height="100dp" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal" >

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator7"
                android:layout_width="100dp"
                android:layout_height="100dp" />

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator8"
                android:layout_width="100dp"
                android:layout_height="100dp" />

            <com.tutorialsface.circularprogress.ProgressIndicator
                android:id="@+id/determinate_progress_indicator9"
                android:layout_width="100dp"
                android:layout_height="100dp" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

2.1 Open MainActivity.java cpoy below code in it-
package com.tutorialsface.circularprogress;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity{

      ProgressIndicator mProgressIndicator1,mProgressIndicator2, mProgressIndicator3,
                                mProgressIndicator4,mProgressIndicator5,mProgressIndicator6,
                                mProgressIndicator7,mProgressIndicator8,mProgressIndicator9;
      Button btnreset;
      float max = 1;
      float update = 0;
      boolean threadRunning = false;;
     
      @Override
      protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mProgressIndicator1 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator1);
            mProgressIndicator2 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator2);
            mProgressIndicator3 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator3);
            mProgressIndicator4 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator4);
            mProgressIndicator5 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator5);
            mProgressIndicator6 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator6);
            mProgressIndicator7 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator7);
            mProgressIndicator8 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator8);
            mProgressIndicator9 = (ProgressIndicator) findViewById(R.id.determinate_progress_indicator9);
            btnreset = (Button) findViewById(R.id.btnreset);
           
            mProgressIndicator1.setForegroundColor(Color.parseColor("#b0120a"));
            mProgressIndicator1.setBackgroundColor(Color.parseColor("#f69988"));
       
        mProgressIndicator2.setForegroundColor(Color.parseColor("#880e4f"));
        mProgressIndicator2.setBackgroundColor(Color.parseColor("#f48fb1"));
       
        mProgressIndicator3.setForegroundColor(Color.parseColor("#4a148c"));
        mProgressIndicator3.setBackgroundColor(Color.parseColor("#ce93d8"));
       
        mProgressIndicator4.setForegroundColor(Color.parseColor("#2a36b1"));
        mProgressIndicator4.setBackgroundColor(Color.parseColor("#afbfff"));
        mProgressIndicator4.setPieStyle(true);
       
        mProgressIndicator5.setForegroundColor(Color.parseColor("#004d40"));
        mProgressIndicator5.setBackgroundColor(Color.parseColor("#80cbc4"));
        mProgressIndicator5.setPieStyle(true);
       
        mProgressIndicator6.setForegroundColor(Color.parseColor("#0d5302"));
        mProgressIndicator6.setBackgroundColor(Color.parseColor("#72d572"));
        mProgressIndicator6.setPieStyle(true);
       
        mProgressIndicator7.setForegroundColor(Color.parseColor("#f9a825"));
        mProgressIndicator7.setBackgroundColor(Color.parseColor("#fff59d"));
       
        mProgressIndicator8.setForegroundColor(Color.parseColor("#d84315"));
        mProgressIndicator8.setBackgroundColor(Color.parseColor("#ffab91"));
       
        mProgressIndicator9.setForegroundColor(Color.parseColor("#4e342e"));
        mProgressIndicator9.setBackgroundColor(Color.parseColor("#bcaaa4"));
        startThread();
            btnreset.setOnClickListener(new OnClickListener() {
                  @Override
                  public void onClick(View v) {
                        if(threadRunning)
                              return;
                        startThread();
                  }
            });
      }
     
      private void startThread() {
            new Thread(new Runnable() {
                  @Override
                  public void run() {
                        threadRunning = true;
                        update = 0;
                        while(update <= max){
                              update += 0.005;
                          updateProgressIndicatorValue();
                          try{
                              Thread.sleep(100);
                          }catch(Exception e){
                             
                          }
                        }
                        threadRunning = false;
                  }
            }).start();
      }
     
   private void updateProgressIndicatorValue() {
         this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
              mProgressIndicator1.setValue(update);
              mProgressIndicator2.setValue(update);
              mProgressIndicator3.setValue(update);
              mProgressIndicator4.setValue(update);
              mProgressIndicator5.setValue(update);
              mProgressIndicator6.setValue(update);
              mProgressIndicator7.setValue(update);
              mProgressIndicator8.setValue(update);
              mProgressIndicator9.setValue(update);
            }
         });
    }
}

Download Source Code Download 


5 comments:

  1. Great, Awesome , share as Library on Github..:)

    ReplyDelete
  2. why is the max value not working with values higher than 1 ? i am trying to make a progress bar for my fitness app and if i set the max as 10000 (steps) and try to give update the value from the API it will display the bar but full, and it dose not matter what value is set to update it will display the progress bar as full

    ReplyDelete