luispadron / UICircularProgressRing

A circular progress bar for iOS written in Swift
MIT License
1.73k stars 290 forks source link

Ring value not setting up #222

Closed Scanbird closed 4 years ago

Scanbird commented 4 years ago

Hi

This seems to me a strange behavior but maybe I did not understand something from the documentation.

If I setup the Ring.value before adding the Ring to the view hierarchy, the value shows and when I startProgress(...) it starts from there the animation.

If I setup the Ring.value somewhere else, like after pressing a button and before startProgress(), everything starts from 0. Although the line is not there anymore, I did try Ring.setNeedsDisplay() to update the visual.

This is test code, but on the official app, I will need the Ring to show progression on a 14 hours period. The app wont be visible all the time, so I need to set the value from where we are when the app open before starting the animation.

import UIKit
import UICircularProgressRing

class ViewController: UIViewController {

    let progressRing = UICircularProgressRing()

    override func viewDidLoad() {
        super.viewDidLoad()
        prepareRingView()
        self.view.addSubview(progressRing)
    }

    func prepareRingView() {
        progressRing.fullCircle = false
        progressRing.startAngle = 135
        progressRing.endAngle = 45
        progressRing.style = .inside
        progressRing.minValue = 0
        progressRing.maxValue = 14
        progressRing.valueKnobStyle = .default
        progressRing.valueFormatter = UICircularProgressRingFormatter(valueIndicator: " Hr", rightToLeft: false,                                     showFloatingPoint: true, decimalPlaces: 1)
        progressRing.gradientOptions = UICircularRingGradientOptions(startPosition: .left, endPosition: .right, colors: [.green, .yellow, .orange], colorLocations: [0, 0.4, 0.9])
        progressRing.frame = CGRect(x: UIScreen.main.bounds.midX - 100,
                                    y: UIScreen.main.bounds.midY - 100,
                                    width: 200, height: 200)
        progressRing.animationTimingFunction = .linear
        progressRing.value = 2  /// Good at visual, starts from there
    }

    @IBAction func buttonPressed(_ sender: Any) {
        let initialTI = 300 - (progressRing.value * 300) / 14
        //progressRing.value = 2  ///Does set to 2, starts from 0
        print("Value 1: \(progressRing.value)")
        progressRing.startProgress(to: 14, duration: TimeInterval(initialTI))
        progressRing.continueProgress()
        print("Initial : \(initialTI)")
    }

}

Thank you

XCode 11, Swift 5.1

luispadron commented 4 years ago

Hi could you try:

progressRing.startProgress(to: 2, duration: 0) in the buttonPressed function and see if that does what you want?

You also don't need to call continueProgress unless you called pauseProgress before.

Scanbird commented 4 years ago

Hi

With progressRing.value = 2 commented in prepareRingView and uncommented in buttonPressed, if duration is either 0 or initialTI in progressRing.startProgress(to: 2, duration: [whateverValue]) it does the same thing : instantly goes to 2 and stop.

In my research, I did use the delegate/protocol to use the didUpdateProgressValue. That's where I found out that although the print("Value 1 ...") of line 3 of the buttonPressed gives 2, startProgress() resets it to 0.

Thank you for your help

Scanbird commented 4 years ago

Hi.

I found a workaround.

As I thought that things were happening too fast for the value to be properly propagated to the control properties, I thought of slowing things down. Starting the animation after a small delay made everything works perfectly smooth.

progressRing.value = valueToStartFrom DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(250)) { self.progressRing.startProgress(to: self.progressRing.maxValue, duration: self.progressDuration )}

2 milliseconds was the lowest working delay for me, although I put 250 because over a 14hrs period it is not significant.

Keep your good product alive

luispadron commented 4 years ago

You can also try something like:

progressRing.startProgress(to: valueToStartFrom, duration: 0) {
    // ring value now valueToStartFrom
   self.progressRing.startProgress(to: self.progressRing.maxValue, duration: self.progressDuration)
}