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
JavaScript: Object Literal Reference in Own Key'S Function Instead of 'This'
JavaScript and Operator Within Assignment
Prevent Address-Bar Hiding in Mobile Browsers
How to Make Changeable Themes Using CSS and JavaScript
Resetting the Opacity of a Child Element - Maple Browser (Samsung Tv App)
Performance Impact of Using CSS/JavaScript Source-Maps in Production
Copy to Clipboard Using JavaScript in iOS
How to Use a Ruby Loop Inside of Haml's :JavaScript Region
Window Is Not Defined in Next.Js React App
Cross-Browser JavaScript Xml Parsing
Meaning of "This" in Node.Js Modules and Functions
Leaflet Map Not Displayed Properly Inside Tabbed Panel
Webkit and Jquery Draggable Jumping
Flex Items Not Shrinking When Window Gets Smaller
How to Use JavaScript to Check and Load CSS If Not Loaded