Core Animation Enter The Matrix
Core Animation Enter The Matrix
Who am I?
Senior Lead Developer with Odyssey Computing, Inc. 14 years industry experience In-house development & project consulting Programming for mobile since 1999!
++ C
# C
Obj-C
Windows iOS
Course Materials
available for download
Outline
Intro to matrices APIs Quartz 2D CGAffineTransform CATransform3D
Outline
Intro to matrices APIs Animations Basic Keyframe Fold Flip
non-retina display
(0,0) 320 (320,0)
480 480
(0,480)
retina display
640 (640,0)
(0,480)
(320,480) 960
(0,960)
(640,960)
What is a matrix?
A way to transform user space Translate - move left/right, up/down Scale - make bigger/smaller Rotate - spin
a d g
b e h
c f i
1 0 0
0 1 0
0 0 1 =
a d g
b e h
c f i
1 0 0
0 1 0
0 0 1
a d g
b e h
c f i =
a d g
b e h
c f i
M1
M2
M3
M4
Mn
1 0 0 M Minv = 0 1 0 0 0 1
1 0 0 Minv M = 0 1 0 0 0 1
x y 1
a c tx
b d ty
0 0 1 =
ax + by + tx cx + dy + ty
1
x y 1
1 0 0
0 1 0
0 0 1 =
1x + 0y + 0z x
y 0x + 1y + 0z 1
x y 1
1 0 0
0 1 0
0 0 1 =
1x + 0y + 0z x
y 0x + 1y + 0z 1
Basic operations
Translation Scale Rotation
Translation
(0,0) 320 (320,0)
480
(0,480)
(320,480)
Translation
(0,0) 320 (320,0)
480
(0,480)
(320,480)
Scale
(0,0) 320 (320,0)
480
(0,480)
(320,480)
Scale
(0,0) 320 (320,0)
480
(0,480)
(320,480)
Rotation
(0,0) 320 (320,0)
480
(0,480)
(320,480)
Rotation
(0,0) 320 (320,0)
480
(0,480)
(320,480)
Quartz 2D
Quartz 2D
CGContextConcat CGContextConcatCTM CGContextGet CGContextGetCTM CGContextTranslate CGContextTranslateCTM CGContextScale CGContextScaleCTM CGContextRotate CGContextRotateCTM CTM = Current Transformation Matrix
Quartz 2D
Concat Get Translate Scale Rotate applies transform to CTM gets the CTM
CGContextTranslateCTM
Drawing - drawRect:
- (void)drawRect:(CGRect)rect { // Drawing code # CGContextRef context = UIGraphicsGetCurrentContext(); [[UIColor blackColor] setStroke]; # CGContextTranslateCTM(context, 60, 140); // Translate # [[UIColor blackColor]setFill]; blueColor] setStroke]; UIBezierPath *path = [UIBezierPath bezierPathWithRect: # [[UIColor blueColor] setFill]; # ( CGRect){{0,0}, [UIBezierPath bezierPathWithRect: # UIBezierPath *path = {200,200}}]; [path fill]; # # (CGRect){{0,0}, {200,200}}]; # [path fill]; stroke]; } # [path stroke]; }
(0,0)
320
(320,0)
480
(0,480)
(320,480)
CGContextTranslateCTM
Drawing - drawRect:
- (void)drawRect:(CGRect)rect { // Drawing code # CGContextRef context = UIGraphicsGetCurrentContext(); # [[UIColor blackColor] setStroke]; 140); // Translate CGContextTranslateCTM(context, 60, # [[UIColor blueColor] setFill]; blackColor] setStroke]; # UIBezierPath *path = [UIBezierPath bezierPathWithRect: [[UIColor blueColor] setFill]; # # (CGRect){{0,0}, [UIBezierPath bezierPathWithRect: UIBezierPath *path = {200,200}}]; # [path CGRect){{0,0}, {200,200}}]; # ( fill]; # [path stroke]; fill]; } [path stroke]; # }
(0,0)
320
(320,0)
480
(0,480)
(320,480)
CGContextScaleCTM
Drawing - drawRect:
- (void)drawRect:(CGRect)rect { // Drawing code # CGContextRef context = UIGraphicsGetCurrentContext(); # CGContextTranslateCTM(context, 60, 140); // Translate # [[UIColor blackColor] setStroke]; CGContextScaleCTM(context, 0.5, 0.5); // Scale # [[UIColor blueColor] setFill]; blackColor] setStroke]; # UIBezierPath *path = [UIBezierPath bezierPathWithRect: [[UIColor blueColor] setFill]; # # (CGRect){{0,0}, [UIBezierPath bezierPathWithRect: UIBezierPath *path = {200,200}}]; # [path CGRect){{0,0}, {200,200}}]; # ( fill]; # [path stroke]; fill]; } [path stroke]; # }
(0,0)
320
(320,0)
480
(0,480)
(320,480)
CGContextRotateCTM
Drawing - drawRect:
- (void)drawRect:(CGRect)rect { // Drawing code # CGContextRef context = UIGraphicsGetCurrentContext(); # CGContextTranslateCTM(context, 60, 140); // Translate # CGContextScaleCTM(context, 0.5, 0.5); // Scale # [[UIColor blackColor] setStroke]; CGContextRotateCTM(context, radians(60)); // Rotate # [[UIColor blueColor] setFill]; blackColor] setStroke]; # UIBezierPath *path = [UIBezierPath bezierPathWithRect: [[UIColor blueColor] setFill]; # # (CGRect){{0,0}, [UIBezierPath bezierPathWithRect: UIBezierPath *path = {200,200}}]; # [path CGRect){{0,0}, {200,200}}]; # ( fill]; # [path stroke]; fill]; } [path stroke]; # }
(0,0)
320
(320,0)
480
(0,480)
(320,480)
Quartz 2D drawing
A way to draw some lines
- (void)drawRect:(CGRect)rect { // Drawing code # CGContextRef context = UIGraphicsGetCurrentContext(); # CGContextSetLineWidth(context, 2); # [[UIColor redColor] setStroke]; # # for (int i = 1; i <= 7; i++) # { # # CGContextMoveToPoint(context, 40 * i, 0); # # CGContextAddLineToPoint(context, 40 * i, 200); # } # # CGContextStrokePath(context); }
(0,0)
320
(320,0)
480
(0,480)
(320,480)
Quartz 2D drawing
A better way to draw some lines
- (void)drawRect:(CGRect)rect { // Drawing code # CGContextRef context = UIGraphicsGetCurrentContext(); # [[UIColor redColor] setStroke]; # # UIBezierPath *path = [UIBezierPath bezierPath]; # [path moveToPoint:(CGPoint){0, 0}]; # [path addLineToPoint:(CGPoint){0, 200}]; # [path setLineWidth:2]; # # # # # # # # # } CGContextSaveGState(context); for (int i = 1; i <= 7; i++) { # CGContextTranslateCTM(context, 40, 0); # [path stroke]; } CGContextRestoreGState(context);
(0,0)
320
(320,0)
480
(0,480)
(320,480)
DEMO
CGContext CTM methods
CGAffineTransform
CGAffineTransform
2D UIView transform property (animatable) CALayer affineTransform & setAffineTransform convenience methods (indirectly animatable)
CGAffineTransform
CGAffineTransform
Identity
CGAffineTransformIdentity
[view setTransform:CGAffineTransformIdentity];
CGAffineTransform
Creating Transforms
CGAffineTransform
Modifying Transforms
CGAffineTransformTranslate CGAffineTransformScale CGAffineTransformRotate CGAffineTransformInvert CGAffineTransformConcat
CGAffineTransform
Creating vs. Modifying
Create
CGAffineTransformMake CGAffineTransformMakeTranslation CGAffineTransformMakeScale CGAffineTransformMakeRotation
Modify
CGAffineTransformConcat CGAffineTransformTranslate CGAffineTransformScale CGAffineTransformRotate CGAffineTransformInvert
Translation
UIView *square = [[UIView alloc] initWithFrame: # (CGRect){{0,0}, {200,200}}]; [square setBackgroundColor:[UIColor blueColor]]; [self.view addSubview:square]; // Translate CGAffineTransform transform = # CGAffineTransformMakeTranslation(60, 140); [square setTransform:transform];
(0,0)
320
(320,0)
480
[square frame]
Translation
UIView *square = [[UIView alloc] initWithFrame: # (CGRect){{0,0}, {200,200}}]; [square setBackgroundColor:[UIColor blueColor]]; [self.view addSubview:square]; // Translate CGAffineTransform transform = # CGAffineTransformMakeTranslation(60, 140); [square setTransform:transform];
(0,0)
320
(320,0)
480
[square frame]
Scale
UIView *square = [[UIView alloc] initWithFrame: # (CGRect){{0,0}, {200,200}}]; [square setBackgroundColor:[UIColor blueColor]]; [self.view addSubview:square]; // Translate CGAffineTransform transform = # CGAffineTransformMakeTranslation(60, 140); // Scale transform = CGAffineTransformScale(transform, 0.5, 0.5); [square setTransform:transform];
(0,0)
320
(320,0)
480
[square frame]
Rotation
UIView *square = [[UIView alloc] initWithFrame: # (CGRect){{0,0}, {200,200}}]; [square setBackgroundColor:[UIColor blueColor]]; [self.view addSubview:square]; // Translate CGAffineTransform transform = # CGAffineTransformMakeTranslation(60, 140); // Scale transform = CGAffineTransformScale(transform, 0.5, 0.5); // Rotate transform = CGAffineTransformRotate(transform, radians(60)); [square setTransform:transform];
(0,0)
320
(320,0)
480
[square frame]
CGAffineTransform
Applying Transforms
CGPointApplyAffineTransform CGSizeApplyAffineTransform CGRectApplyAffineTransform
CGAffineTransform
Evaluating Transforms
CGAffineTransformIsIdentity CGAffineTransformEqualToTransform
DEMO
CGAffineTransform
CATransform3D
CATransform3D
3D CALayer transform property (animatable) can convert to CGAffineTransform if 2D (z =0)
CATransform3D
/* Homogeneous three-dimensional transforms. */ struct CATransform3D { CGFloat m11, m12, m13, CGFloat m21, m22, m23, CGFloat m31, m32, m33, CGFloat m41, m42, m43, };
CATransform3D
Transforming 3D points
x y z 1
m11 m12 m13 m14 m21 m22 m23 m24 m31 m32 m33 m34 m41 m42 m43 m44 =
m11x + m21y + m31z + m41 m12x + m22y + m32z + m42 m13x + m23y + m33z + m43 m14x + m24y + m34z + m44
CATransform3D
m34 Skew - creates 3D perspective
x y z 1
m11 m12 m13 m14 m21 m22 m23 m24 m31 m32 m33 m34 m41 m42 m43 m44 =
m11x + m21y + m31z + m41 m12x + m22y + m32z + m42 m13x + m23y + m33z + m43 m14x + m24y + m34z + m44
CATransform3D
Identity
CATransform3DIdentity
[layer setTransform:CATransform3DIdentity];
CATransform3D
Creating Transforms
CATransform3D
Modifying Transforms
CATransform3DTranslate CATransform3DScale CATransform3DRotate CATransform3DInvert CATransform3DConcat
CATransform3D
Creating vs. Modifying
Create
CATransform3DMake CATransform3DMakeTranslation CATransform3DMakeScale CATransform3DMakeRotation
Modify
CATransform3DConcat CATransform3DTranslate CATransform3DScale CATransform3DRotate CATransform3DInvert
CATransform3D
Converting to/from Affine
CATransform3DGetAffineTransform CATransform3DMakeAffineTransform
CATransform3D
Evaluating Transforms
CATransform3DIsIdentity CATransform3DEqualToTransform CATransform3DIsAffine
DEMO
CATransform3D
Basic Animations
Basic Animations
1. Create a CGAffineTransform 2. call setTransform on UIView within an animation block 3. Done!
Basic Animations
- (void)rotateView:(UIView *)view byAngle:(CGFloat)angle { [UIView animateWithDuration:0.5 # # # # # # delay:0 options:UIViewAnimationCurveEaseInOut animations:^{ # # # # # # CGAffineTransform transform = [view transform]; # # # # # # transform = CGAffineTransformRotate(transform, angle); # # # # # # [view setTransform:transform]; # # # # # } # # # # # completion:nil ]; }
DEMO
Basic Animations
Keyframe Animations
Keyframe Animations
Q: When do you need them? A: When you want to animate a CGPathRef A: When the built-in timing curves dont suit your needs
Keyframe Animations
// Create the animation (we're animating transform property) CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; // set our keyframe values [animation setValues:[NSArray arrayWithArray:array]]; # # [animation setDuration:duration]; [animation setTimingFunction: [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]]; [animation setRemovedOnCompletion:YES]; // add the animation [self.arc.layer addAnimation:animation forKey:@"transform"]; // set final state NSValue* toValue = [animation.values lastObject]; [self.arc.layer setTransform:[toValue CATransform3DValue]];
DEMO
Keyframe Animation
Fold Animation
Fold Animation
Top Middle Bottom
Fold Animation
cut view into 4 pieces render each as UIImageView Top Middle Top Half Middle Bottom Half Bottom
Fold Animation
Top fold here Middle Top Half Middle Bottom Half Bottom bend here
Fold Animation
move down Top Middle Top Half Middle Bottom Half move up Bottom
Fold Animation
Top Middle Top Half Middle Bottom Half Bottom
Fold Animation
Top Middle Top Half Middle Bottom Half Bottom rotate around x-axis in opposite direction set skew for perspective
Fold Animation
Top Middle Top Half Middle Bottom Half Bottom
Fold Animation
Top Bottom
DEMO
Fold Animation
Flip Animation
Flip Animation
Top
Bottom
Flip Animation
cut current and next views into 2 pieces each render each as UIImageView
Current Top
Current Bottom
Flip Animation
Flip Animation
Flip Animation
Current Top
Current Bottom
Next Bottom
Flip Animation
Current Top
Current Bottom
Next Bottom
Flip Animation
Flip Animation
previous view being obscured
Current Top
Next Top
Next Bottom
Flip Animation
Current Top
Next Top
Next Bottom
Flip Animation
Next Top
Next Bottom
Animation complete!
DEMO
Flip Animation
Further Reading
Transforms, Quartz 2D Programming Guide (Apple) Layer Geometry and Transforms, Core Animation Programming Guide (Apple) Graphics and Drawing in iOS, Drawing and Printing Guide for iOS (Apple)
Questions?
Odyssey Computing, Inc.
5820 Oberlin Dr, Suite 202 San Diego, CA 92121 Twitter: Email: Phone: Web: @mpospese [email protected] 914.282.3519 www.odysseyinc.com
Contact
Odyssey Computing, Inc.
5820 Oberlin Dr, Suite 202 San Diego, CA 92121 Twitter: Email: Phone: Web: @mpospese [email protected] 914.282.3519 www.odysseyinc.com