Core & UIKit Animation
Dimitri James Tsiflitzis
CocoaheadsSKG
Why use animation in your apps?
- Assist in learning
- Highlights visual queues
- Natural look & feel
- Provides meaning
- App effectiveness & performance
Architecture
Hardware
OpenGL
Core Animation
UIKit
GPU
Examples of animations you can perform on layers
Move
Scale
Text
Rotate
Transparency
Radius
Colour
Layers
CALayer
CAShapeLayer
CATiledLayer
CAScrollLayer
CATextLayer
CAReplicationLayer
Creating a layer
CALayer *myLayer = [CALayer layer];
myLayer.frame = CGRectMake(0,0,width,height);
myLayer.position = CGPointMake(30.0,67.0);
myLayer.content = mylogo;
[self.layer addSubLayer:myLayer];
Creating animations
Animation types
- Implicit
- Explicit
Implicit
- Simply change a layer property
mario.position = CGPoint.init(x: 10.0, y: 10.0)
Explicit
- More direct / fine grained Control
- Classes
- CABasicAnimation
- CAKeyframeAnimation
- CAAnimationGroup
Explicit animation
CAAnimation
CAAnimationGroup
CAPropertyAnimation
CATransition
CABasicAnimation
CAKeyframeAnimation
CABasicAnimation
- Animation for a (
stringly typed) key path- "position"
- "transform.rotation.z"
- "backgroundColor"
- Set to & from properties
- Add the animation to the desired layer to kick off the animation
CABasicAnimation
let animation = CABasicAnimation.init(keyPath: "transform.rotation.z")
animation.fromValue = 0.0
animation.toValue = CGFloat(M_PI * 2.0)
animation.duration = 5.0
animation.repeatCount = Float(UInt8.max)
view.layer.add(animation, forKey: "rotationAnimation")
CAKeyframeAnimation
- More "advanced" behaviour
- Animate across a "key frame" group
- Path (CGPathRef)
- Values (Array)
CAKeyframeAnimation
- Layer transformations with CATransform3D
- Can set the transform property
CAKeyframeAnimation
func pulseAnimation() -> CAKeyframeAnimation {
let pulseAnimation = CAKeyframeAnimation()
pulseAnimation.keyPath = "transform";
pulseAnimation.values = [
NSValue.init(caTransform3D: CATransform3DMakeScale(1.0, 1.0, 1.0)),
NSValue.init(caTransform3D: CATransform3DMakeScale(1.03, 0.97, 1.0)),
NSValue.init(caTransform3D: CATransform3DMakeScale(1.0, 1.0, 1.0)),
NSValue.init(caTransform3D: CATransform3DMakeScale(0.97, 1.03, 1.0)),
NSValue.init(caTransform3D: CATransform3DMakeScale(1.0, 1.0, 1.0))
]
pulseAnimation.keyTimes =
[0.0, NSNumber.init(value:1.0 / 4.0), NSNumber.init(value:1.0 / 2.0), NSNumber.init(value:3.0 / 4.0), 1.0];
pulseAnimation.repeatCount = Float(NSIntegerMax);
pulseAnimation.autoreverses = true
return pulseAnimation;
}
CAAnimationGroup
- An object that allows multiple animations to be grouped and run concurrently.
- 60fps
CAAnimationGroup
func wobble() {
// 1
var wobbleAnimation1: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation1.fromValue = ovalPathLarge.CGPath
wobbleAnimation1.toValue = ovalPathSquishVertical.CGPath
wobbleAnimation1.beginTime = 0.0
wobbleAnimation1.duration = animationDuration
// 2
var wobbleAnimation2: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation2.fromValue = ovalPathSquishVertical.CGPath
wobbleAnimation2.toValue = ovalPathSquishHorizontal.CGPath
wobbleAnimation2.beginTime = wobbleAnimation1.beginTime + wobbleAnimation1.duration
wobbleAnimation2.duration = animationDuration
// 3
var wobbleAnimation3: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation3.fromValue = ovalPathSquishHorizontal.CGPath
wobbleAnimation3.toValue = ovalPathSquishVertical.CGPath
wobbleAnimation3.beginTime = wobbleAnimation2.beginTime + wobbleAnimation2.duration
wobbleAnimation3.duration = animationDuration
// 4
var wobbleAnimation4: CABasicAnimation = CABasicAnimation(keyPath: "path")
wobbleAnimation4.fromValue = ovalPathSquishVertical.CGPath
wobbleAnimation4.toValue = ovalPathLarge.CGPath
wobbleAnimation4.beginTime = wobbleAnimation3.beginTime + wobbleAnimation3.duration
wobbleAnimation4.duration = animationDuration
// 5
var wobbleAnimationGroup: CAAnimationGroup = CAAnimationGroup()
wobbleAnimationGroup.animations = [wobbleAnimation1, wobbleAnimation2, wobbleAnimation3,
wobbleAnimation4]
wobbleAnimationGroup.duration = wobbleAnimation4.beginTime + wobbleAnimation4.duration
wobbleAnimationGroup.repeatCount = 2
addAnimation(wobbleAnimationGroup, forKey: nil)
}
CAAnimationGroup
UIKit Animations
UIKit Animations
- Wrapper around CALayer
- Uses Core Animation under the hood
- Very easy to use
- Offer event handling
- Less properties to animate than layers
- No rounded corners
- Easy for stock animations, drop down to Core Animations for more complex functionality
UIKit Animations prehistory
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.30];
self.alpha = 0.5f;
[UIView commitAnimations];
UIKit Animations now
[UIView animateWithDuration:0.1f animations:^{
self.alpha = 0.5f;
}];
UIKit Animations block based API
animateWithDuration:
animations:
animateWithDuration:
animations:
completion:
animateWithDuration:
delay:
options:
animations:
completion:
UIKit Animation options
- Bit mask for behaviour
- Autoreverse or repeating
- Enabling user intercation
- Animation curves
- Beginning from current state
Why Core Animation?
#define DURATION (1.2)
@interface ViewController () {
NSTimer *animationTimer;
NSInteger animationCount;
NSInteger numberIterations;
CGPoint startPosition;
CGPoint endPosition;
}
@end
Why Core Animation?
@implementation ViewController
- (IBAction)doAnimation:(id)sender {
animationTimer = [NSTimer
scheduledTimerWithTimeInterval:1./60.
target:self
selector:@selector(updateAnimation:)
userInfo:nil
repeats:YES];
animationCount = 0;
numberIterations = 60. * DURATION;
startPosition = self.targetView.frame.origin;
if (50. == startPosition.x) {
endPosition = self.bottomRight;
} else {
endPosition = CGPointMake(50., 50.);
}
}
Why Core Animation?
- (void)updateAnimation:(id)timer {
animationCount++;
if (numberIterations == animationCount) {
[animationTimer invalidate];
}
CGRect targetFrame = self.targetView.frame;
CGFloat endWeight = 1. * animationCount / numberIterations;
CGFloat startWeight = 1. - endWeight;
targetFrame.origin = CGPointMake(
startWeight * startPosition.x + endWeight * endPosition.x,
startWeight * startPosition.y + endWeight * endPosition.y);
self.targetView.frame = targetFrame;
}
iOS10 property animators
- Create gesture based animations
- Create interruptible animations
iOS10 property animators
let alphaChange = UIViewPropertyAnimator(duration: 0.3, dampingRatio: 0.6,
animations: { [weak self] in
self?.circleView.alpha = 0.0
})
// To run an animation
alphaChange.startAnimation()
//To pause an animator
alphaChange.pauseAnimation()
// For a gesture recognizer or delegate that reports every step
// of its progress (e.g. UIPanGestureRecognizer or a ScrollViewDidScroll) you can just apply the percentage
// directly to the UIViewPropertyAnimator object
@IBAction func handlePan(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
let translatedCenterY = view.center.y + translation.y
let progress = translatedCenterY / self.view.bounds.size.height
alphaChange.fractionComplete = progress
}
Thank you!
Core & UIKit Animation
By tsif
Core & UIKit Animation
- 223