From 05ad80b7074eadb3131543292b11f18837d91e6b Mon Sep 17 00:00:00 2001 From: featherless Date: Fri, 22 Dec 2017 11:03:12 -0500 Subject: [PATCH] Add core animation quiz to the readme. (#108) --- README.md | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/README.md b/README.md index 1a7dec1..3ab81e2 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,147 @@ MotionAnimator is a purely Core Animation-based animator. If you are looking for - [POP](https://github.com/facebook/pop) - [CADisplayLink](https://developer.apple.com/documentation/quartzcore/cadisplaylink) +# Core Animation: a deep dive + +> Recommended reading: +> +> - [Building Animation Driven Interfaces](http://asciiwwdc.com/2010/sessions/123) +> - [Core Animation in Practice, Part 1](http://asciiwwdc.com/2010/sessions/424) +> - [Core Animation in Practice, Part 2](http://asciiwwdc.com/2010/sessions/425) +> - [Building Interruptible and Responsive Interactions](http://asciiwwdc.com/2014/sessions/236) +> - [Advanced Graphics and Animations for iOS Apps](http://asciiwwdc.com/2014/sessions/419) +> - [Advances in UIKit Animations and Transitions](http://asciiwwdc.com/2016/sessions/216) +> - [Animating Layer Content](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html) +> - [Advanced Animation Tricks](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/AdvancedAnimationTricks/AdvancedAnimationTricks.html) +> - [Additive animations: animateWithDuration in iOS 8](http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/) + +There are two primary ways to animate with Core Animation on iOS: + +1. **implicitly**, with the UIView `animateWithDuration:` APIs, or by setting properties on standalone CALayer instances (those that are **not** backing a UIView), and +2. **explicitly**, with the CALayer `addAnimation:forKey:` APIs. + +A subset of UIView's and CALayer's public APIs is animatable by Core Animation. Of these animatable properties, some are implicitly animatable while some are not. Whether a property is animatable or not depends on the context within which it's being animated, and whether an animation is additive or not depends on which animation API is being used. With this matrix of conditions it's understandable that it can sometimes be difficult to know how to effectively make use of Core Animation. + +The following quiz helps illustrate that the UIKit and Core Animation APIs can often lead to unintuitive behavior. Try to guess which of the following snippets will generate an animation and, if they do, what the generated animation's duration will be: + +> Imagine that each code snippet is a standalone unit test (because [they are](tests/unit/HeadlessLayerImplicitAnimationTests.swift)!). + +```swift +let view = UIView() +UIView.animate(withDuration: 0.8, animations: { + view.alpha = 0.5 +}) +``` + +
+ Click to see the answer + Generates an animation with duration of 0.8. +
+ +--- + +```swift +let view = UIView() +UIView.animate(withDuration: 0.8, animations: { + view.layer.opacity = 0.5 +}) +``` + +
+ Click to see the answer + Generates an animation with duration of 0.8. +
+ +--- + +```swift +let view = UIView() +UIView.animate(withDuration: 0.8, animations: { + view.layer.cornerRadius = 3 +}) +``` + +
+ Click to see the answer + On iOS 11 and up, generates an animation with duration of 0.8. Older operating systems will not generate an animation. +
+ +--- + +```swift +let view = UIView() +view.alpha = 0.5 +``` + +
+ Click to see the answer + Does not generate an animation. +
+ +--- + +```swift +let view = UIView() +view.layer.opacity = 0.5 +``` + +
+ Click to see the answer + Does not generate an animation. +
+ +--- + +```swift +let layer = CALayer() +layer.opacity = 0.5 +``` + +
+ Click to see the answer + Does not generate an animation. +
+ +--- + +```swift +let view = UIView() +window.addSubview(view) +let layer = CALayer() +view.layer.addSublayer(layer) + +// Pump the run loop once. +RunLoop.main.run(mode: .defaultRunLoopMode, before: .distantFuture) + +layer.opacity = 0.5 +``` + +
+ Click to see the answer + Generates an animation with duration of 0.25. +
+ +--- + +```swift +let view = UIView() +window.addSubview(view) +let layer = CALayer() +view.layer.addSublayer(layer) + +// Pump the run loop once. +RunLoop.main.run(mode: .defaultRunLoopMode, before: .distantFuture) + +UIView.animate(withDuration: 0.8, animations: { + layer.opacity = 0.5 +}) +``` + +
+ Click to see the answer + Generates an animation with duration of 0.25. This isn't a typo: standalone layers read from the current CATransaction rather than UIView's parameters when implicitly animating, even when the change happens within a UIView animation block. +
+ ## Example apps/unit tests Check out a local copy of the repo to access the Catalog application by running the following