Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test whether a UIView is in the middle of animation

People also ask

What is the difference between UIView and CALayer?

Working with UIViews happens on the main thread, it means it is using CPU power. CALayer: Layers on other hand have simpler hierarchy. That means they are faster to resolve and quicker to draw on the screen. There is no responder chain overhead unlike with views.

Does UIView animate run on the main thread?

The contents of your block are performed on the main thread regardless of where you call [UIView animateWithDuration:animations:] . It's best to let the OS run your animations; the animation thread does not block the main thread -- only the animation block itself.

Does UIView animate need weak self?

You don't need to use [weak self] in static function UIView. animate() You need to use weak when retain cycle is possible and animations block is not retained by self.

Is UIView animate asynchronous?

UIView. animate runs on the main thread and is asynchronous.


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.


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.


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

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


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.


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.


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.