核心是 layer objects,
Like views, layer objects have a bounds rectangle, a position onscreen, an opacity, a transform, and many other visually-oriented properties that can be modified. 更改這些屬性的時候有隱式動畫,可以明確指定動畫行為。
隱式layer動畫是使用 action objects。可以創建自己的 action objects ,實現自定義動畫,或者也能實現其他類型的行為。
先熟悉 View Programming Guide for iOS.
Layer objects 對核心。layer只是管理內容和可視化屬性,所以可以將layer想成 model 對象
對於 view 中調用 drawRect: 方法,非常的損耗,因為這在線程上使用CPU。核心動畫通過在硬件上緩存位圖來達到同樣或相似的效果。
layer 也有像view 有的一些屬性,frame bounds,並且也有類似 anchor poing(錨點)這種 view 沒有的屬性。
point-based coordinate systems 和 unit coordinate systems
通常使用 point-based 坐標系指定 layer 的大小和位置,
unit coordinate system (單位坐標系)是用來表示當 layer 的大小變化的時候哪些屬性可能改變。可以認為單位坐標系指定所有可能變化值的百分比。
Core Animation Functions Reference.
有3個 layer 對象集合:
model layer tree 中的對象是模型對象,存儲動畫的目標值 presentation tree包含動畫運行中的值。你應該從來都不要去修改這個 tree 中的對象。使用這些對象讀取當前動畫的值,或者使用這些值開始新的動畫。 render tree 中的對象執行實際的動畫,這是核心動畫私有的
layer 不是 view 的替代品,不能單獨靠layer 對象創建一個可視化的界面。layer 提供了 view 的基礎。layer 使得view內容的繪制和動畫更加有效,並且動畫有較高的幀率,就是更流暢。layer不能處理事件,不能繪制內容,不能參與到響應鏈等等。所以應用必須有一個或多個 view 來處理這種交互
重寫 layerClass 類方法 返回想要替換的 類對象。
指定 view 的 layer 類
+ (Class) layerClass { return [CAMetalLayer class]; }
CALayer子類及其用法
3種方式給layer的位圖提供數據:
直接給layer對象的 contents 屬性賦值一個 image 對象。這是最好的方法 給layer賦值一個代理對象,並讓代理繪制 layer 的內容。(適合內容周期性的變化,比如隨著 view變化) 定義一個 layer 子類,並重寫一個它的繪制方法將image 賦值給 layer必須是 CGImageRef 類型。
代理實現 displayLayer: 方法
- (void)displayLayer:(CALayer *)theLayer { // Check the value of some state property if (self.displayYesImage) { // Display the Yes image theLayer.contents = [someHelperObject loadStateYesImage]; } else { // Display the No image theLayer.contents = [someHelperObject loadStateNoImage]; } }
代理實現 drawLayer:inContext: 方法
- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext { CGMutablePathRef thePath = CGPathCreateMutable(); CGPathMoveToPoint(thePath,NULL,15.0f,15.f); CGPathAddCurveToPoint(thePath, NULL, 15.f,250.0f, 295.0f,250.0f, 295.0f,15.0f); CGContextBeginPath(theContext); CGContextAddPath(theContext, thePath); CGContextSetLineWidth(theContext, 5); CGContextStrokePath(theContext); // Release the path CFRelease(thePath); }
layer 的 contentsGravity 屬性模式的設置是 kCAGravityResize 常量。
iOS 不能給 layer 對象添加過濾器
精確的動畫,需要創建一個 CABasicAnimation 對象,使用這個對象來配置參數。
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeAnim.fromValue = [NSNumber numberWithFloat:1.0]; fadeAnim.toValue = [NSNumber numberWithFloat:0.0]; fadeAnim.duration = 1.0; [theLayer addAnimation:fadeAnim forKey:@"opacity"]; // Change the actual data value in the layer to the final value. theLayer.opacity = 0.0;
// create a CGPath that implements two arcs (a bounce) CGMutablePathRef thePath = CGPathCreateMutable(); CGPathMoveToPoint(thePath,NULL,74.0,74.0); CGPathAddCurveToPoint(thePath,NULL,74.0,500.0, 320.0,500.0, 320.0,74.0); CGPathAddCurveToPoint(thePath,NULL,320.0,500.0, 566.0,500.0, 566.0,74.0); CAKeyframeAnimation * theAnimation; // Create the animation object, specifying the position property as the key path. theAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; theAnimation.path=thePath; theAnimation.duration=5.0; // Add the animation to the layer. [theLayer addAnimation:theAnimation forKey:@"position"];
removeAnimationForKey: removeAllAnimations
只能移除顯示動畫,不能移除隱式動畫。
// Animation 1 CAKeyframeAnimation* widthAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderWidth"]; NSArray* widthValues = [NSArray arrayWithObjects:@1.0, @10.0, @5.0, @30.0, @0.5, @15.0, @2.0, @50.0, @0.0, nil]; widthAnim.values = widthValues; widthAnim.calculationMode = kCAAnimationPaced; // Animation 2 CAKeyframeAnimation* colorAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderColor"]; NSArray* colorValues = [NSArray arrayWithObjects:(id)[UIColor greenColor].CGColor, (id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, nil]; colorAnim.values = colorValues; colorAnim.calculationMode = kCAAnimationPaced; // Animation group CAAnimationGroup* group = [CAAnimationGroup animation]; group.animations = [NSArray arrayWithObjects:colorAnim, widthAnim, nil]; group.duration = 5.0; [myLayer addAnimation:group forKey:@"BorderChanges"];
There are two different ways to be notified about the state of an animation:
Add a completion block to the current transaction using the setCompletionBlock: method. When all of the animations in the transaction finish, the transaction executes your completion block. Assign a delegate to your CAAnimation object and implement the animationDidStart: and animationDidStop:finished: delegate methods.[UIView animateWithDuration:1.0 animations:^{ // Change the opacity implicitly. myView.layer.opacity = 0.0; // Change the position explicitly. CABasicAnimation* theAnim = [CABasicAnimation animationWithKeyPath:@"position"]; theAnim.fromValue = [NSValue valueWithCGPoint:myView.layer.position]; theAnim.toValue = [NSValue valueWithCGPoint:myNewPosition]; theAnim.duration = 3.0; [myView.layer addAnimation:theAnim forKey:@"AnimateFrame"]; }];
bounds 、position
myLayer.bounds = CGRectMake(0, 0, 100, 100); myLayer.position = CGPointMake(200, 200);
重點:對於 layer 的寬高總是使用整數
speed 屬性,動畫速度的倍數。
Core Animation supports several options for adjusting the size and position of sublayers in response to changes to their superlayer. In iOS, the pervasive use of layer-backed views makes the creation of layer hierarchies less important; only manual layout updates are supported. For OS X, several other options are available that make it easier to manage your layer hierarchies
masksToBounds 屬性設置 YES,就可以啟用自動裁剪
還有 convertTime:fromLayer 和 convertTime:toLayer
創建 CATransition 對象 ,並添加給 layer。
Listing 5-1 shows the code used to create an animated push transition between two views. In the example, both myView1 and myView2 are located at the same position in the same parent view but only myView1 is currently visible. The push transition causes myView1 to slide out to the left and fade until it is hidden while myView2 slides in from the right and becomes visible. Updating the hidden property of both views ensures that the visibility of both views is correct at the end of the animation.
CATransition* transition = [CATransition animation]; transition.startProgress = 0; transition.endProgress = 1.0; transition.type = kCATransitionPush; transition.subtype = kCATransitionFromRight; transition.duration = 1.0; // Add the transition animation to both layers [myView1.layer addAnimation:transition forKey:@"transition"]; [myView2.layer addAnimation:transition forKey:@"transition"]; // Finally, change the visibility of the layers. myView1.hidden = YES; myView2.hidden = NO;
CAMediaTiming 協議。CAAnimation 和 CALayer 都遵守了這個協議。
#import#import #import /* The CAMediaTiming protocol is implemented by layers and animations, it * models a hierarchical timing system, with each object describing the * mapping from time values in the object's parent to local time. * * Absolute time is defined as mach time converted to seconds. The * CACurrentMediaTime function is provided as a convenience for querying the * current absolute time. * * The conversion from parent time to local time has two stages: * * 1. conversion to "active local time". This includes the point at * which the object appears in the parent's timeline, and how fast it * plays relative to the parent. * * 2. conversion from active to "basic local time". The timing model * allows for objects to repeat their basic duration multiple times, * and optionally to play backwards before repeating. */ @class NSString; NS_ASSUME_NONNULL_BEGIN @protocol CAMediaTiming /* The begin time of the object, in relation to its parent object, if * applicable. Defaults to 0. */ @property CFTimeInterval beginTime; /* The basic duration of the object. Defaults to 0. */ @property CFTimeInterval duration; /* The rate of the layer. Used to scale parent time to local time, e.g. * if rate is 2, local time progresses twice as fast as parent time. * Defaults to 1. */ @property float speed; /* Additional offset in active local time. i.e. to convert from parent * time tp to active local time t: t = (tp - begin) * speed + offset. * One use of this is to "pause" a layer by setting `speed' to zero and * `offset' to a suitable value. Defaults to 0. */ @property CFTimeInterval timeOffset; /* The repeat count of the object. May be fractional. Defaults to 0. */ @property float repeatCount; /* The repeat duration of the object. Defaults to 0. */ @property CFTimeInterval repeatDuration; /* When true, the object plays backwards after playing forwards. Defaults * to NO. */ @property BOOL autoreverses; /* Defines how the timed object behaves outside its active duration. * Local time may be clamped to either end of the active duration, or * the element may be removed from the presentation. The legal values * are `backwards', `forwards', `both' and `removed'. Defaults to * `removed'. */ @property(copy) NSString *fillMode; @end /* `fillMode' options. */ CA_EXTERN NSString * const kCAFillModeForwards __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0); CA_EXTERN NSString * const kCAFillModeBackwards __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0); CA_EXTERN NSString * const kCAFillModeBoth __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0); CA_EXTERN NSString * const kCAFillModeRemoved __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0); NS_ASSUME_NONNULL_END
得到 layer 的當前 local time
CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];
-(void)pauseLayer:(CALayer*)layer { CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; layer.speed = 0.0; layer.timeOffset = pausedTime; } -(void)resumeLayer:(CALayer*)layer { CFTimeInterval pausedTime = [layer timeOffset]; layer.speed = 1.0; layer.timeOffset = 0.0; layer.beginTime = 0.0; CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; layer.beginTime = timeSincePause; }
CATransaction 類
創建顯式的 transaction
[CATransaction begin]; theLayer.zPosition=200.0; theLayer.opacity=0.0; [CATransaction commit];
修改動畫的默認持續時間
[CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:10.0f] forKey:kCATransactionAnimationDuration]; // Perform the animations [CATransaction commit];
嵌套顯式 transaction
[CATransaction begin]; // Outer transaction // Change the animation duration to two seconds [CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration]; // Move the layer to a new position theLayer.position = CGPointMake(0.0,0.0); [CATransaction begin]; // Inner transaction // Change the animation duration to five seconds [CATransaction setValue:[NSNumber numberWithFloat:5.0f] forKey:kCATransactionAnimationDuration]; // Change the zPosition and opacity theLayer.zPosition=200.0; theLayer.opacity=0.0; [CATransaction commit]; // Inner transaction [CATransaction commit]; // Outer transaction
給 parent layer 添加透視變化
CATransform3D perspective = CATransform3DIdentity; perspective.m34 = -1.0/eyePosition; // Apply the transform to a parent layer. myParentLayer.sublayerTransform = perspective;
CAAction 協議
/** Action (event handler) protocol. **/ @protocol CAAction /* Called to trigger the event named 'path' on the receiver. The object * (e.g. the layer) on which the event happened is 'anObject'. The * arguments dictionary may be nil, if non-nil it carries parameters * associated with the event. */ - (void)runActionForKey:(NSString *)event object:(id)anObject arguments:(nullable NSDictionary *)dict; @end
核心動畫尋找 action 對象的順序:
如果 layer 有一個 delegate, 並且delegate 實現了 actionForLayer:forKey 方法,layer調用這個方法。delegate 必須做下面幾件事之一:使用 layer 代理對象提供 action
- (id)actionForLayer:(CALayer *)theLayer forKey:(NSString *)theKey { CATransition *theAnimation=nil; if ([theKey isEqualToString:@"contents"]) { theAnimation = [[CATransition alloc] init]; theAnimation.duration = 1.0; theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; theAnimation.type = kCATransitionPush; theAnimation.subtype = kCATransitionFromRight; } return theAnimation; }
Temporarily disabling a layer’s actions
[CATransaction begin]; [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; [aLayer removeFromSuperlayer]; [CATransaction commit];
drawsAsynchronously 屬性
Layer Style Property Animations
Animatable Properties