简体   繁体   中英

UIView.animateWithDuration completes too early when changing view with Tab Bar Controller

I am making a progress bar by increasing the with of a simple image:

let progressBar = createProgressBar(width: self.view.frame.width, height: 60.0)
let progressBarView = UIImageView(image: progressBar)
progressBarView.frame = CGRect(x: 0, y: 140, width: 0, height: 60)
UIView.animateWithDuration(60.0, delay: 0.0, options: [], animations: {
    progressBarView.frame.size.width = self.backgroundView.frame.size.width
    }, completion: {_ in
        print("progress completed")
    }
)

This works as expected, but I am having problems when changing views using a TabBarController. When I change view, I would like the progress bar to continue animating in the background, such that I can go back to this view to check on progress, but instead it does end immediately when I change views, and the completion block is called.

Why does this happen, and how to fix it?

When you tap another tabBar item, the viewController that is performing animation will be in a state of viewDidDisappear and the animation will be removed.

Actually, it is not recommended to perform any animation when the viewController is not presented in the front of the screen.

To continue the interrupted animation progress, you have to maintain the current states of the animation and restore them when the tabBar item switched back.

For example, you may hold some instance variables to keep the duration, progress, beginWidth and endWidth of the animation. And you can restore the animation in viewDidAppear :

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    // `self.duration` is the total duration of the animation. In your case, it's 60s.
    // `self.progress` is the time that had been consumed. Its initial value is 0s.
    // `self.beginWidth` is the inital width of self.progressBarView.
    // `self.endWidth`, in your case, is `self.backgroundView.frame.size.width`.

    if self.progress < self.duration {

        UIView.animateWithDuration(self.duration - self.progress, delay: 0, options: [.CurveLinear], animations: {

            self.progressBarView.frame.size.width = CGFloat(self.endWidth)
            self.beginTime = NSDate() // `self.beginTime` is used to track the actual animation duration before it interrupted.

            }, completion: { finished in
                if (!finished) {
                    let now = NSDate()
                    self.progress += now.timeIntervalSinceDate(self.beginTime!)
                    self.progressBarView.frame.size.width = CGFloat(self.beginWidth + self.progress/self.duration * (self.endWidth - self.beginWidth))
                } else {
                    print("progress completed")
                }
            }
        )
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM