Count Down Timer with Circular Progress Bar

Circular Progress Bar ( for a countdown timer )

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();

}

CountDown Timer with CircularProgressIndicator

Your progress isn't calculated correctly.

progressIndicator.progress = (millisUntilFinished / 1000).toInt()

If millisUntilFinished == 59000, you will end up with a progress of 59. You should be calculating a percentage here instead of this.

How to Create a circular progressbar with CountDown in Android

For these type of progress bar,
try one of these two libraries that are on GitHub:

https://github.com/Todd-Davies/ProgressWheel

https://github.com/f2prateek/progressbutton?source=c

CountDownTImer With Circular Progressbar in Android

There are a few libraries the best in my opinion is CircularProgress

How to create a circular progress indicator for a count down timer

You can do it using CAShapeLayer and animating the stroke end as follow:

update Xcode 9 • Swift 4

define the time left

let timeLeftShapeLayer = CAShapeLayer()
let bgShapeLayer = CAShapeLayer()
var timeLeft: TimeInterval = 60
var endTime: Date?
var timeLabel = UILabel()
var timer = Timer()
// here you create your basic animation object to animate the strokeEnd
let strokeIt = CABasicAnimation(keyPath: "strokeEnd")

define a method to create de UIBezierPath

startAngle at -90˚ and endAngle 270

func drawBgShape() {
bgShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: view.frame.midX , y: view.frame.midY), radius:
100, startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath
bgShapeLayer.strokeColor = UIColor.white.cgColor
bgShapeLayer.fillColor = UIColor.clear.cgColor
bgShapeLayer.lineWidth = 15
view.layer.addSublayer(bgShapeLayer)
}
func drawTimeLeftShape() {
timeLeftShapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: view.frame.midX , y: view.frame.midY), radius:
100, startAngle: -90.degreesToRadians, endAngle: 270.degreesToRadians, clockwise: true).cgPath
timeLeftShapeLayer.strokeColor = UIColor.red.cgColor
timeLeftShapeLayer.fillColor = UIColor.clear.cgColor
timeLeftShapeLayer.lineWidth = 15
view.layer.addSublayer(timeLeftShapeLayer)
}

add your Label

func addTimeLabel() {
timeLabel = UILabel(frame: CGRect(x: view.frame.midX-50 ,y: view.frame.midY-25, width: 100, height: 50))
timeLabel.textAlignment = .center
timeLabel.text = timeLeft.time
view.addSubview(timeLabel)
}

at viewDidload set the endTime and add your CAShapeLayer to your view:

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.94, alpha: 1.0)
drawBgShape()
drawTimeLeftShape()
addTimeLabel()
// here you define the fromValue, toValue and duration of your animation
strokeIt.fromValue = 0
strokeIt.toValue = 1
strokeIt.duration = timeLeft
// add the animation to your timeLeftShapeLayer
timeLeftShapeLayer.add(strokeIt, forKey: nil)
// define the future end time by adding the timeLeft to now Date()
endTime = Date().addingTimeInterval(timeLeft)
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}

when updating the time

@objc func updateTime() {
if timeLeft > 0 {
timeLeft = endTime?.timeIntervalSinceNow ?? 0
timeLabel.text = timeLeft.time
} else {
timeLabel.text = "00:00"
timer.invalidate()
}
}

you can use this extension to convert the degrees to radians and display time

extension TimeInterval {
var time: String {
return String(format:"%02d:%02d", Int(self/60), Int(ceil(truncatingRemainder(dividingBy: 60))) )
}
}
extension Int {
var degreesToRadians : CGFloat {
return CGFloat(self) * .pi / 180
}
}

Sample project

Circular progress bar for a countdown timer publisher SwiftUI

You can create a computed property in TimeManager that calculates the progress:

extension TimerManager {
var progress: CGFloat {
return CGFloat(timeRemaining / timeSelected)
}
}

But you also need a trigger for the observers to tell them that it's changed.

Since this value depends on a timeRemaining property, which is @Published, it would work because the observing object will notice a change and ask for the computed value again (which would also change).

Alternatively, you can call self.objectWillChange.send() inside the .sink to notify that an object will change, and that will accomplish the same thing.

Once you have that, you can just refer to it directly in your views:

ProgressBar(progress: self.timer.progress)

(and change ProgressBar so that its .progress property isn't a binding.

Show actual progress from countdowntimer in ProgressBar

you should set the maximum of progress to the number from where count down begins.
e.g if the count down begins from 60.
you should set progressBar.setMax(60)

then also at each countdown set the value for progress bar
e.g progressBar.setValue(59) , then 58 , then 57....
the progressbar will work the way you want.

Circular Progress Bar with Swift UI

You might need to divide endFraction by 10,

Circle().trim(from: 0, to: countDownTimer.counter / 10) // Dividing by 10
.stroke(Color(.systemTeal), style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .bevel))
.aspectRatio(contentMode: .fit)
.rotationEffect(Angle(degrees: -90))
.padding()

Thanks!

Countdown Timer with Progressbar not show progress

First, you need to remove the android:indeterminate="true" from XML use progress bar like this without that attribute

  <ProgressBar
android:id="@+id/progressbartimer"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:min="0"
android:visibility="visible" />

And set progress in updateTimer() like this

 public void updatetimer() {
double progress = (60000 - millisUntilFinished) / 1000; // I have hardcoded max timer value i.e 60000 milliseconds i.e 60s
progressBar.setProgress((int) progress);

int minute = (int) timeleftinmilisecond/60000;
int second = (int) timeleftinmilisecond % 60000 / 1000;

String timelefttxt;
timelefttxt = "" + minute;
timelefttxt += ":";
if(second < 10) timelefttxt += "0";
timelefttxt += second;

timertv.setText(timelefttxt);
}

Note : You might need to set the android:max attribute to 60 if you are using
this code



Related Topics



Leave a reply



Submit