Test whether a UIView is in the middle of animation

IosCocoa TouchUiviewCore AnimationUiviewanimation

Ios Problem Overview


Is there any way to tell if a UIView is in the middle of an animation? When I print out the view object while it is moving I notice that there is an "animations" entry:

search bar should end editing: <UISearchBar: 0x2e6240; frame = (0 0; 320 88); text = ''; autoresize = W+BM; animations = { position=<CABasicAnimation: 0x6a69c40>; bounds=<CABasicAnimation: 0x6a6d4d0>; }; layer = <CALayer: 0x2e6e00>>

When the animation has stopped and I print the view, the "animations" entry is now gone:

search bar should end editing: <UISearchBar: 0x2e6240; frame = (0 0; 320 88); text = ''; autoresize = W+BM; layer = <CALayer: 0x2e6e00>>

Ios Solutions


Solution 1 - Ios

A UIView has a layer (CALayer). You can send animationKeys to it, which will give you an array of keys which identify the animations attached to the layer. I suppose that if there are any entries, the animation(s) are running. If you want to dig even deeper have a look at the CAMediaTiming protocol which CALayer adopts. It does some more information on the current animation.

Important: If you add an animation with a nil key ([layer addAnimation:animation forKey:nil]), animationKeys returns nil.

Solution 2 - Ios

iOS 9+ method, works even when layer.animationKeys contains no keys:

let isInTheMiddleOfAnimation = UIView.inheritedAnimationDuration > 0

From the docs:

> This method only returns a non-zero value if called within a UIView > animation block.

Solution 3 - Ios

Animations are attached in fact to the underlying Core Animation CALayer class

So I think you can just check myView.layer.animationKeys

Solution 4 - Ios

I'm not sure of the context of the question but I had was attempting to find out if a view was animating before starting a second animation to avoid skipping. However there is a UIView animation option UIViewAnimationOptionBeginFromCurrentState that will combine the animations if necessary to give a smooth appearance. Thereby eliminating my need to know if the view was animating.

Solution 5 - Ios

There are a lot of out-of-date answers here. I just needed to prevent a UIView animation being started if there was one running on the same view, so I created a category on UIView:-

extension UIView {

    var isAnimating: Bool {
        return (self.layer.animationKeys()?.count ?? 0) > 0
    }

}

This way I can just check any view's animation status like this:-

if !myView.isAnimating {
  UIView.animate(withDuration: 0.4) {
    ...
  }
} else {
  // already animating
}

This seems less fragile than keeping track of it with a state variable.

Solution 6 - Ios

There is a hitch with the animationKeys trick.

Sometimes there could be a few animationKeys lingering after an animation is completed.

This means that a non-animating layer could return a set of animationKeys even if it isn't actually animating.

You can make sure that animationKeys are automatically removed by setting an animation's removedOnCompletion property to YES.

e.g.

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"aPath"];
animation.removedOnCompletion = YES;

If you do this for all the animations you apply to your layer, it will ensure that when the layer isn't animating there are no animationKeys present.

Solution 7 - Ios

Some of these didn't work for me. The reason for that is that these animations are asynchronous.

What I did is defined a property

@property BOOL viewIsAnimating;

And in my animation

[UIView animateWithDuration:0.25
                 animations:^{
                     viewIsAnimating = YES;
                 } completion:^(BOOL finished) {
                     if (finished) {
                         viewIsAnimating = NO;
                     }
                 }];

Solution 8 - Ios

Ref to the question: https://stackoverflow.com/questions/40096501/uiview-center-position-during-animation

I compare the view's frame and layer.presentation()?.frame to check it is animating. If leftView is on the way to finish, the leftView.layer.presentation()?.frame does not equal to its frame:

if self.leftView.layer.presentation()?.frame == self.leftView.frame {
   // the animation finished
} else {
   // the animation on the way
}

But this method may not work if the view move to the end position during the animation. More condition check may be necessary.

Solution 9 - Ios

Solution 10 - Ios

You can use the layer property of a UIView. CALayer has a property called animation keys, you can check its count if it is greater than 0.

if (view.layer.animationKeys.count) {

  // Animating

}else {

// No

}

In the Documentation:

-(nullable NSArray<NSString *> *)animationKeys;

> Returns an array containing the keys of all animations currently * > attached to the receiver. The order of the array matches the order * > in which animations will be applied.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionprostockView Question on Stackoverflow
Solution 1 - IosNick WeaverView Answer on Stackoverflow
Solution 2 - IosdeejView Answer on Stackoverflow
Solution 3 - IosVincent GuerciView Answer on Stackoverflow
Solution 4 - IosRyan PoolosView Answer on Stackoverflow
Solution 5 - IosEchelonView Answer on Stackoverflow
Solution 6 - IosC4 - TravisView Answer on Stackoverflow
Solution 7 - IosMendyKView Answer on Stackoverflow
Solution 8 - IosBill ChanView Answer on Stackoverflow
Solution 9 - IosHeikoGView Answer on Stackoverflow
Solution 10 - Iosvrat2801View Answer on Stackoverflow