21

I need to handle a case where you can do something with or without animation, instead of:

if (animation)
{
    [UIView animateWithBlock:^(){...}];
}
else
{
    ...
}

I want to do:

[UIView animateWithBlock:^(){...} duration:(animation ? duration : 0)]

but not sure if it works, even if it does, is there any overhead for using this instead of directly change the view?

Thanks

hzxu
  • 5,753
  • 11
  • 60
  • 95

7 Answers7

31

What I do in this cases, is to create a block that contains all the animations I want to make. Then execute an UIView animation passing the animation block as a parameter, or directly calling that block, whether I want it to be animated or not. Something like this :

void (^animationBlock)();
animationBlock=^{
      // Your animation code goes here
};
if (animated) {
    [UIView animateWithDuration:0.3 animations:animationBlock completion:^(BOOL finished) {

    }];
}else{
    animationBlock();
}

That would avoid the overhead

Daniel García
  • 612
  • 4
  • 9
22

According to the Apple docs:

If the duration of the animation is 0, this block is performed at the beginning of the next run loop cycle.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
chebur
  • 614
  • 8
  • 16
  • 1
    So it may not be actually 0 delays from the time the animation statement is executed? – hzxu Mar 19 '13 at 06:10
  • 2
    @hzxu exactly. The effect is the same as calling `[self performSelector:@selector(animate) afterDelay:0]` – chebur Apr 03 '13 at 13:16
  • I can confirm this is indeed the case. Using 0 is not equal to not animating and performing it immediately. – strange Apr 19 '14 at 22:39
8

Yes, since the duration is zero, the transition will effectively by instantaneous.

PappaSmalls
  • 349
  • 2
  • 13
  • 3
    And does it have any overhead? ie. `[UIView animateWithBlock:^(){self.view.frame = newFrame} withDuration:0]` vs `self.view.frame = newFrame`? – hzxu Nov 13 '12 at 22:39
  • You would need to set the frame first so it will act like any other frame. - Yes it will have an overhead. – PappaSmalls Nov 13 '12 at 22:44
  • 13
    I tested this with iOS 7.1.1 5S and the difference is huge; setting a random frame for a view 10k times took 22.85 seconds with ^animateWithBlock:^ and 0.05 seconds with a direct call to the block. However, if you're preforming only a few animation calls for some user interaction, the difference is not relevant. Please note that Apple might change the behavior and optimize this edge case in the future. – mkko Jun 29 '14 at 21:23
  • 3
    This answer is no longer accurate. A setting of 0 will not occur instantaneously, it will take a default period of time somewhere close to 0.25sec. – jasonjwwilliams Feb 13 '19 at 17:33
4

I wrote this little Swift extension to overcome the issue:

extension UIView {

/// Does the same as animate(withDuration:animations:completion:), yet is snappier for duration 0
class func animateSnappily(withDuration duration: TimeInterval, animations: @escaping () -> Swift.Void, completion: (() -> Swift.Void)? = nil) {
    if duration == 0 {
        animations()
        completion?()
    }
    else {
        UIView.animate(withDuration: duration, animations: animations, completion: { _ in completion?() })
    }
}
}

One can use it as a replacement for UIView.animate(withDuration:animations:completion) and doesn't have to make any more thoughts about duration 0.

fredpi
  • 8,414
  • 5
  • 41
  • 61
2

Okay, I have further observation on this. Firsth, there is a performance overhead when using the animation with zero duration but the more profound difference is that the animation's completion block is handled async. This means that first hiding and then displaying the view might not get you the result you expected.

So, no, I would definitely suggest not to use the zero as a duration as it's not synchronous.

mkko
  • 4,262
  • 3
  • 25
  • 29
0

you can set animateWithDuration value dynamically as per requirement.

If You set 0. it means no animation transition time.So, View will be appear without any animation. IF you want provide animation, set some value more than 0.

    **float animationDurationValue=0.03f;
        [UIView animateWithDuration:x delay:0.0f options:UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse 
animations:^{
                             [yourView setFrame:CGRectMake(0.0f, 100.0f, 300.0f, 200.0f)];
                         }
                         completion:nil];**

Please let me know if any issue.

Amit Singh
  • 2,644
  • 21
  • 20
0

As answered, it is not. Here is an example of how to do it in swift.

let setHighlighted: (Bool) -> Void = { [weak self] highlighted in
   if highlighted {
      self?.cardView.alpha = 0.6
   } else {
      self?.cardView.alpha = 1.0
   }
 }

 if animated {
    UIView.animate(withDuration: yourDuration) {
       setHighlighted(highlighted)
    }
 } else {
    setHighlighted(highlighted)
 }
Marc
  • 11,341
  • 3
  • 27
  • 30