18

Ok so I have a countdown timer of 15 seconds that works perfectly fine and I'd like to make a custom circular progress bar for that timer.

I want to create a full circle that gets "slices of the pie (circle)" taken out as the timer goes down until there is no longer a circle.

I'd prefer to make the shapes myself than use pre-made images because I'd like the quality to be good on any phone. How would I go about this? Thanks!

Houcine
  • 22,593
  • 13
  • 53
  • 83
David Baez
  • 1,068
  • 1
  • 11
  • 24

3 Answers3

29

I found this example very good: http://mrigaen.blogspot.it/2013/12/create-circular-progress-bar-in-android.html

So I created my progress bar in this way

<ProgressBar
    android:id="@+id/barTimer"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:layout_centerInParent="true"
    android:progressDrawable="@drawable/circular_progress_bar" />

Then I made a function for the countdown where:

private void startTimer(final int minuti) {
    countDownTimer = new CountDownTimer(60 * minuti * 1000, 500) {
        // 500 means, onTick function will be called at every 500 milliseconds

        @Override
        public void onTick(long leftTimeInMilliseconds) {
            long seconds = leftTimeInMilliseconds / 1000;
            int barVal= (barMax) - ((int)(seconds/60*100)+(int)(seconds%60));
            barTimer.setProgress(barVal);
            textTimer.setText(String.format("%02d", seconds/60) + ":" + String.format("%02d", seconds%60));
            // format the textview to show the easily readable format

        }
        @Override
        public void onFinish() {
            if(textTimer.getText().equals("00:00")){
                textTimer.setText("STOP");          
            }
            else{
                textTimer.setText("2:00");
            }
        }
    }.start();

}

UPDATE

private void startTimer(final int minuti) {
    countDownTimer = new CountDownTimer(60 * minuti * 1000, 500) {
        // 500 means, onTick function will be called at every 500 milliseconds

        @Override
        public void onTick(long leftTimeInMilliseconds) {
            long seconds = leftTimeInMilliseconds / 1000;
            barTimer.setProgress((int)seconds);
            textTimer.setText(String.format("%02d", seconds/60) + ":" + String.format("%02d", seconds%60));
            // format the textview to show the easily readable format

        }
        @Override
        public void onFinish() {
            if(textTimer.getText().equals("00:00")){
                textTimer.setText("STOP"); 
            }
            else{
                textTimer.setText("2:00");
                barTimer.setProgress(60*minuti);
            }
        }
    }.start();

}  
Grancein
  • 602
  • 9
  • 19
  • In this line, int barVal= (barMax) - ((int)(seconds/60*100)+(int)(seconds%60)); - What is barMax? – Aerrow Oct 07 '14 at 12:13
  • what is barMax? @Grace Pii – Xplosive Jan 14 '15 at 20:16
  • BarMax is the max value from which the countdown timer should start. In my case, bacause of I begin from 2 minutes, barMax is 2 minutes. And then I subtract seconds from it! – Grancein Jan 15 '15 at 09:15
  • @GracePii I tried this function, but I am getting error at barMax, I am getting null pointer exception. what is the value you given to barMax? – Kogile Feb 17 '16 at 05:55
  • How I wrote above, BarMax is the value from which the countdown timer starts. I wanted that it started from 2 minutes so I put barMax=2 minutes. I have changed the code since i wrote this post. Now it is as i wrote in the update above. – Grancein Feb 17 '16 at 11:42
  • @GracePii I started this timer as `startTimer(2);` textview started to change its value but progress bar didn't. – Anshul Tyagi Sep 13 '16 at 09:43
  • Have you set the progress bar max value? – Grancein Sep 13 '16 at 12:11
5

Smooth circle progress bar timer

XML Layout:

activity_main

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:id="@+id/reativelayout"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:fitsSystemWindows="true">

<ProgressBar
    android:id="@+id/progressbar_timerview"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="260dp"
    android:layout_height="260dp"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:layout_gravity="center_horizontal|bottom"
    android:indeterminate="false"
    android:progressDrawable="@drawable/circleshape2_timerview" />

 <TextView
    android:id="@+id/textView_timerview_time"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:alpha="0.6"
    android:background="@drawable/circleshape_timerview"
    android:gravity="center"
    android:text="00:00"
    android:textColor="@android:color/black"
    android:textSize="20sp"
    android:textStyle="bold" />

 <ProgressBar
    android:id="@+id/progressbar1_timerview"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="260dp"
    android:layout_height="260dp"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:layout_gravity="center_horizontal|center"
    android:indeterminate="false"
    android:progressDrawable="@drawable/circleshape1_timerview"
    android:visibility="gone" />

<Button
    android:id="@+id/button_timerview_start"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_centerHorizontal="true"
    android:background="@android:color/transparent"
    android:text="Start !"
    android:textAllCaps="false"
    android:textSize="20sp"
    android:textStyle="italic" />


 <Button
    android:id="@+id/button_timerview_stop"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_centerHorizontal="true"
    android:background="@android:color/transparent"
    android:text="Stop !"
    android:layout_marginTop="30dp"
    android:textAllCaps="false"
    android:textSize="20sp"
    android:visibility="invisible"
    android:textStyle="italic"
    />

<EditText
    android:id="@+id/textview_timerview_back"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:gravity="center"
    android:padding="5dp"
    android:layout_marginBottom="30dp"
    android:textSize="35sp"
    android:hint=""/>
  </RelativeLayout>

Drawable file:

circleshape2_timerview

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/progress">
        <shape
            android:innerRadiusRatio="5"
            android:shape="ring"
            android:thicknessRatio="20.0"

            android:useLevel="false"
            android:visible="true">
            <gradient
                android:centerColor="#FF00"
                android:endColor="#FF00"
                android:startColor="#FF00ff"
                android:type="sweep" />
        </shape>
    </item>
</layer-list>

circleshape1_timerview

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/progress">
        <rotate
            android:fromDegrees="270"
            android:toDegrees="-90">
            <shape
                android:innerRadiusRatio="5"
                android:shape="ring"
                android:thicknessRatio="20.0"

                android:useLevel="true"
                android:visible="true">
                <gradient
                    android:centerColor="#FF00"
                    android:endColor="#FF00"
                    android:startColor="#FF00ff"
                    android:type="sweep" />
            </shape>
        </rotate>

    </item>
</layer-list>

circleshape_timerview

 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 <item>
    <shape android:shape="oval">

        <solid android:color="#bbb"/>
    </shape>
 </item>
 </selector>

Activity:

MainActivity

 import android.app.Activity;
 import android.os.Bundle;
 import android.os.CountDownTimer;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;

 public class MainActivity extends Activity implements OnClickListener {

int i = -1;
ProgressBar mProgressBar, mProgressBar1;

private Button buttonStartTime, buttonStopTime;
private EditText edtTimerValue;
private TextView textViewShowTime;
private CountDownTimer countDownTimer;
private long totalTimeCountInMilliseconds;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    buttonStartTime = (Button) findViewById(R.id.button_timerview_start);
    buttonStopTime = (Button) findViewById(R.id.button_timerview_stop);

    textViewShowTime = (TextView)  
    findViewById(R.id.textView_timerview_time);
    edtTimerValue = (EditText) findViewById(R.id.textview_timerview_back);

    buttonStartTime.setOnClickListener(this);
    buttonStopTime.setOnClickListener(this);

    mProgressBar = (ProgressBar) findViewById(R.id.progressbar_timerview);
    mProgressBar1 = (ProgressBar) findViewById(R.id.progressbar1_timerview);

  }
  @Override
  public void onClick(View v) {
    if (v.getId() == R.id.button_timerview_start) {

        setTimer();

        buttonStartTime.setVisibility(View.INVISIBLE);
        buttonStopTime.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.INVISIBLE);

        startTimer();
        mProgressBar1.setVisibility(View.VISIBLE);


    } else if (v.getId() == R.id.button_timerview_stop) {
        countDownTimer.cancel();
        countDownTimer.onFinish();
        mProgressBar1.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.VISIBLE);
        edtTimerValue.setVisibility(View.VISIBLE);
        buttonStartTime.setVisibility(View.VISIBLE);
        buttonStopTime.setVisibility(View.INVISIBLE);
    }
 }
  private void setTimer(){
    int time = 0;
    if (!edtTimerValue.getText().toString().equals("")) {
        time = Integer.parseInt(edtTimerValue.getText().toString());
    } else
        Toast.makeText(MainActivity.this, "Please Enter Minutes...",  
  Toast.LENGTH_LONG).show();
    totalTimeCountInMilliseconds =  time * 1000;
    mProgressBar1.setMax( time * 1000);
   }
   private void startTimer() {
    countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 1) {
        @Override
        public void onTick(long leftTimeInMilliseconds) {
            long seconds = leftTimeInMilliseconds / 1000;
            mProgressBar1.setProgress((int) (leftTimeInMilliseconds));

            textViewShowTime.setText(String.format("%02d", seconds / 60)
                    + ":" + String.format("%02d", seconds % 60));
        }
        @Override
        public void onFinish() {
            textViewShowTime.setText("00:00");
            textViewShowTime.setVisibility(View.VISIBLE);
            buttonStartTime.setVisibility(View.VISIBLE);
            buttonStopTime.setVisibility(View.VISIBLE);
            mProgressBar.setVisibility(View.VISIBLE);
            mProgressBar1.setVisibility(View.GONE);

        }
    }.start();
 }
 }
Manoz
  • 13
  • 5
4

For creating custom components, please check Android API Guide. Excerpt for Basic Approach:

  1. Extend an existing View class or subclass with your own class.
  2. Override some of the methods from the superclass. The superclass methods to override start with 'on', for example, onDraw(), onMeasure(), and onKeyDown(). This is similar to the on... events in Activity or ListActivity that you override for lifecycle and other functionality hooks.
  3. Use your new extension class. Once completed, your new extension class can be used in place of the view upon which it was based.

Also, check Todd Davies' Progress Wheel at https://github.com/Todd-Davies/ProgressWheel, this should get you started.

Melquiades
  • 8,316
  • 1
  • 27
  • 40