UIView animateWithDuration and UIProgressView setProgress

蓝咒 提交于 2019-11-30 14:37:11

问题


I want to animate my UIProgressView progression from 0 to 1 during 10 seconds.

Code:

[UIView animateWithDuration:10.0 animations:^{
    [_myProgressView setProgress:1 animated:YES];
} completion:(BOOL finished)^{
    if (finished) NSLog(@"animation finished);
}];

Animation is working fine except that completion and NSLog are always called instantly.

I tried animateWithDuration: withDelay: but the delay is not respected and executed immediately.

Has anyone encountered the same problem?

Thanks for you help.


回答1:


Its an old problem but I am still posting the solution here. The solution turned out to be really simple. All you need to do is:

[_myProgressView setProgress:1];
[UIView animateWithDuration:10.0 animations:^{
    [_myProgressView layoutIfNeeded];
} completion:^(BOOL finished){
    if (finished) NSLog(@"animation finished");
}];

Here is a good explanation for why things were working incorrectly for you: http://blog.spacemanlabs.com/2012/08/premature-completion-an-embarrassing-problem/

So you can not use setProgress:animated: method to animate the progress view and get your desired behaviour of completion block as well. However, just setting progress inside the block will not animate it, since progress is not an animatable property.

Refer to apple documentation which says its necessary for the property to be animatable: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/clm/UIView/animateWithDuration:animations:

So you just update the value of progress property outside the animate block and do the layout of the view inside the animate block.




回答2:


Make it simple instead using NSTimer like,

[progressview setProgress:0 animated:NO];
NSTimer *t=[NSTimer scheduledTimerWithTimeInterval: 1.0f
                                         target: self
                                       selector: @selector(progressupdate)
                                       userInfo: nil
                                        repeats: YES];

Below is the function which updates progress,

-(void)progressupdate{
   if(progressview.progress<1){
      [progressview setProgress:(progressview.progress+=0.2) animated:YES];
   }
   else{
      [t invalidate];
   }
} 

Hope it helps....




回答3:


What i found out is a set of both UIview animations and progress view animatons that work much nicer and animate the progressview smoothly. If you just use the combination of animation and progressview animation it is fired directly without regard to the UIview animation timer.

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    timer = [NSTimer scheduledTimerWithTimeInterval: 1.0f
                                             target: self
                                           selector: @selector(updateTimer)
                                           userInfo: nil
                                            repeats: YES];
}


- (void)updateTimer
{
    if (progressView.progress >= 1.0) {
        [timer invalidate];
    }
    [UIView animateWithDuration:1 animations:^{
        float newProgress = [self.progressView progress] + 0.125;
        [self.progressView setProgress:newProgress animated:YES];
    }];
}

Feel free to adjust the animation times to even better and smooth transitions




回答4:


It's an old question, but I had a similar problem and here is my solution (sorry it's in Swift). The completion part is called when the animation finishes. It's inside a custom UIProgressView class.

override func setProgress(progress: Float, animated: Bool) {

    self.progress = progress
    if animated {
        let duration: NSTimeInterval = 10.0
        UIView.animateWithDuration(duration, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: {
            self.layoutIfNeeded()
            }, completion: { (completed) in
                self.animationDuration = nil
        })
    } else {
        self.layoutIfNeeded()
    }
}



回答5:


None of these answers really worked for me. I was able to get the progress to animate, but for some reason it had a delay in the beginning (especially for longer durations).

The key for me, was to call layoutIfNeeded inside an animation block and wait on the completion before doing the 2nd animation . This code is called from viewDidLoad. With the following code, I was able to achieve a perfectly smooth timer animation.

    // For some reason, the first layoutIfNeeded() needs to be wrapped in an animation block, even though it is supposedly a synchronous call.  Otherwise, the progress just jumps right to 100%
    UIView.animate(withDuration: 0.0, animations: {
        self.progressView.layoutIfNeeded()
    }, completion: { finished in
        self.progressView.progress = 1.0

        UIView.animate(withDuration: self.timerDuration, delay: 0.0, options: [.curveLinear], animations: {
            self.progressView.layoutIfNeeded()
        }, completion: { finished in
            print("animation completed")
        })
    })


来源:https://stackoverflow.com/questions/23803464/uiview-animatewithduration-and-uiprogressview-setprogress

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!