Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is it appropriate to use Core Animation over UIView animation in common cases

This is related to a lot of little bugs that might stereotypically be considered minor by one person, but major by another.

What I've noticed more and more, is that when using all flavors a UIView animateWithDuration:, it actually modifies things unnecessarily, such multiple properties of my views', to do a simple hide/reveal style animations, etc..

Things seem to be finicky in scenarios like a UINavigationBar not animating into position properly for a certain rotation transition, or a header view not animating along with the status bar when it's frame updates, when when a view's sublayers would implicitly animate differently when their parent view's properties change...

So many of these I have been revisiting, and converting to CAAnimations because they seem to be easier to manage, in they do not actually modify my views' target property values.

A simple example being, using [view setHidden:], and then animating it or out of view, but the view is actually already visible or hidden while the animation runs.

Another one being, the need to transform/rotate/scale a UINavigationController's view, and using a CAAnimation to do it, because the UINavigationBar does not move to it's correct position if I modify the UINavigationController's view, and any of it's parent view's transform property values.

So in conclusion to this question, I have been back and forth, and have been finding places where one is more appropriate than the other for my circumstances, but mainly, I want to hear what others think about these scenarios, and if there's is some insight into what Apple has provided that I can feel better about my approaches.

Thanks in advance.

like image 319
drkibitz Avatar asked Jul 11 '16 01:07

drkibitz


1 Answers

At the end of the day, all UIKit-style animations are converted to Core Animation-style animations; that is, everything is actually animated using Core Animation. The difference between the APIs is mostly one of convenience: UIKit-style animation functions update the model value, committing an animation to reflect that change over time in the presentation layer.

You have to also be careful that you're animating properties that UIKit says you can animate. For example, while you can technically animate properties on UIScrollView like contentSize and contentOffset, they aren't officially supported, so you have to potentially deal with side effects.

In addition, frame is a special case because it's actually a derived property, composed of center, transform, and bounds (in addition to anchorPoint on CALayer, which UIView does not expose). Animating a view's frame can have a whole host of unintended problems, usually involving rotation. Core Animation doesn't have this problem, because frame is not an explicitly-animatable property on CALayer. Try to use bounds and center in UIKit-style animations if you're encountering weird behavior involving the affine transform (e.g., scale, translate, rotation) of that view.

It's true that animating certain views in UIKit might have unintended side effects or bugs because you're updating model values in addition to animating them. Core Animation, on the other hand, is a little more flexible, because you have fine-grained control over how and when it updates either the model layer or the presentation layer.

But I would disagree that UIKit is modifying things unnecessarily. It modifies what it needs to modify in order to commit the animated changes you request as well as updating its model values. When you're animating properties such as frame, this is going to implicitly invoke layoutSubviews() on that view after the current run loop, which can cascade to other subviews and so on.

If you want UIKit to perform all its layout logic before you animate, then call setNeedsLayout() along with layoutIfNeeded() before you invoke an animation block. If you'd like UIKit to actually animate the entire subview hierarchy's worth of changes at the same time that your animation is committed, specify the UIViewAnimationOptions.layoutSubviews option. This will trigger subview layout immediately, within the animation block, so those values are animated as well. Otherwise, the model values that are changed by your animation will trigger layout updates on the next run loop.

In general, I rarely notice issues using UIKit-style animation functions. So as someone who has spent an extensive amount of time animating on iOS, I would say:

Use UIKit-style animations in every place you can, since they're really convenient. Core Animation-style animations should be used when you run into problems with UIKit-style animations or if you need specific control over how a layer's model and presentation values need to be updated.

like image 177
CIFilter Avatar answered Oct 16 '22 22:10

CIFilter