maxkonovalov / MKRingProgressView

⭕️ Ring progress view similar to Activity app on Apple Watch
MIT License
1.57k stars 136 forks source link

Even/smooth progress #32

Closed okahara closed 6 years ago

okahara commented 6 years ago

We really like this Pod!

We are actually using the progress rings for a timer but love that it looks like the native watch rings. That being said we were wondering if it was possible to make the progress evenly incremented without updating progress every second.

We were doing the update every second but the progress than "stepped". We did the below code once a second in a Timer.scheduleTimer. The variable progress is the % of seconds left (ex: 25/30) with the view saying 25 seconds.

CATransaction.begin() CATransaction.setAnimationDuration(1.0) timer.progress = progress // updated every second CATransaction.commit()

Instead we moved to this approach where we start the Timer and start the progress animation to have a duration of the full countdownSecs (ex: 30 seconds). Note we setup the progress ring before this to have progress = 1.0.

CATransaction.begin() CATransaction.setAnimationDuration(Double(countdownSecs)) timer.progress = 0.0 CATransaction.commit()

We think this looks smoother as an animation but the progress is no longer incrementing in even values.

Example: If the timer is for 30 seconds, when the ring is half full we expect the time to be 15 seconds.

img_1271 img_1273

Is there a way to make this progression even?

maxkonovalov commented 6 years ago

Hello @okahara! Not sure if it helps, but did you try kCAMediaTimingFunctionLinear for the transaction? Seems that uneven animation pacing can be caused by the timing functions implicitly used by Core Animation.

okahara commented 6 years ago

@maxkonovalov That works great! Unfortunately it is something we'd have to change within the pod and we want to be able to easily update to any of your future changes.

Would you allow us to make a pull request to make the CAMediaTimingFunction settable to the predefined timing functions and default to the KCAMediaTimingFunctionDefault that you currently have?

maxkonovalov commented 6 years ago

@okahara sure, no problem, I think this should be a welcome addition really :)

okahara commented 6 years ago

@maxkonovalov awesome! :) I will start working on that

okahara commented 6 years ago

@maxkonovalov I apologize this took so long for us to get to.

After I forked your repo a colleague and I read through your code and realized we could solve this without doing a pull request.

extension MKRingProgressLayer {
    override open func action(forKey event: String) -> CAAction? {
        if event == "progress" {
            let animation = CABasicAnimation(keyPath: event)
            animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
            animation.fromValue = presentation()?.value(forKey: event)
            animation.duration = max(0.01, CATransaction.animationDuration())
            return animation
        }
        return super.action(forKey: event)
    }
}
maxkonovalov commented 6 years ago

@okahara good to know! Feel free to submit a pull request anyway if it works for you better ;) I'm closing this issue for now ✌🏻