CoreAnimation之隱式動(dòng)畫

CoreAnimation之CALayer基礎(chǔ)
CoreAnimation之變換
CoreAnimation之常用圖層

修改非RootLayer的一些屬性(支持隱式動(dòng)畫的屬性)會(huì)產(chǎn)生隱式動(dòng)畫

隱式動(dòng)畫的持續(xù)時(shí)間取決于當(dāng)前事務(wù),隱式動(dòng)畫的類型取決于圖層行為


事務(wù):

事務(wù)實(shí)際上是Core Animation用來包含一系列屬性動(dòng)畫集合的機(jī)制,任何用指定事務(wù)去改變可以做動(dòng)畫的圖層屬性都不會(huì)立刻發(fā)生變化,而是當(dāng)事務(wù)一旦提交的時(shí)候開始用一個(gè)動(dòng)畫過渡到新值

所謂事務(wù),具體到代碼中就是CATransaction類,CATransaction沒有屬性或者實(shí)例方法,并且也不能用+alloc和-init方法創(chuàng)建它,常用方法有這些:

/* Begin a new transaction for the current thread; nests. */

+ (void)begin;

/* Commit all changes made during the current transaction. Raises an
 * exception if no current transaction exists. */

+ (void)commit;

/* Commits any extant implicit transaction. Will delay the actual commit
 * until any nested explicit transactions have completed. */

+ (void)flush;

/* Methods to lock and unlock the global lock. Layer methods automatically
 * obtain this while modifying shared state, but callers may need to lock
 * around multiple operations to ensure consistency. The lock is a
 * recursive spin-lock (i.e shouldn't be held for extended periods). */

+ (void)lock;
+ (void)unlock;

/* Accessors for the "animationDuration" per-thread transaction
 * property. Defines the default duration of animations added to
 * layers. Defaults to 1/4s. */

+ (CFTimeInterval)animationDuration;
+ (void)setAnimationDuration:(CFTimeInterval)dur;

/* Accessors for the "animationTimingFunction" per-thread transaction
 * property. The default value is nil, when set to a non-nil value any
 * animations added to layers will have this value set as their
 * "timingFunction" property. Added in Mac OS X 10.6. */

+ (nullable CAMediaTimingFunction *)animationTimingFunction;
+ (void)setAnimationTimingFunction:(nullable CAMediaTimingFunction *)function;

/* Accessors for the "disableActions" per-thread transaction property.
 * Defines whether or not the layer's -actionForKey: method is used to
 * find an action (aka. implicit animation) for each layer property
 * change. Defaults to NO, i.e. implicit animations enabled. */

+ (BOOL)disableActions;
+ (void)setDisableActions:(BOOL)flag;

/* Accessors for the "completionBlock" per-thread transaction property.
 * Once set to a non-nil value the block is guaranteed to be called (on
 * the main thread) as soon as all animations subsequently added by
 * this transaction group have completed (or been removed). If no
 * animations are added before the current transaction group is
 * committed (or the completion block is set to a different value), the
 * block will be invoked immediately. Added in Mac OS X 10.6. */

#if __BLOCKS__
+ (nullable void (^)(void))completionBlock;
+ (void)setCompletionBlock:(nullable void (^)(void))block;
#endif

/* Associate arbitrary keyed-data with the current transaction (i.e.
 * with the current thread).
 *
 * Nested transactions have nested data scope, i.e. reading a key
 * searches for the innermost scope that has set it, setting a key
 * always sets it in the innermost scope.
 *
 * Currently supported transaction properties include:
 * "animationDuration", "animationTimingFunction", "completionBlock",
 * "disableActions". See method declarations above for descriptions of
 * each property.
 *
 * Attempting to set a property to a type other than its document type
 * has an undefined result. */

+ (nullable id)valueForKey:(NSString *)key;
+ (void)setValue:(nullable id)anObject forKey:(NSString *)key;

事務(wù)有顯式事務(wù)和隱式事務(wù)之分

Core Animation在每個(gè)run loop周期中自動(dòng)開始一次新的事務(wù),即使你不顯式的用[CATransaction begin]開始一次事務(wù),任何在一次run loop循環(huán)中圖層屬性的改變都會(huì)被集中起來,然后做一次0.25秒的動(dòng)畫,即隱式事務(wù)

調(diào)用[CATransaction begin]開始一次事務(wù),即為顯式事務(wù)

舉個(gè)栗子,新開一個(gè)事務(wù),修改layer的backgroundColor:

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    
    [CATransaction begin];
    //修改動(dòng)畫的持續(xù)時(shí)間
    [CATransaction setAnimationDuration:5.0f];
    [CATransaction setCompletionBlock:^{
        NSLog(@"動(dòng)畫完成");
    }];
    layer.backgroundColor = [UIColor blueColor].CGColor;
    [CATransaction commit];
    
}

running.gif

UIView中也有類似的動(dòng)畫機(jī)制:

+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;  // additional context info passed to will start/did stop selectors. begin/commit can be nested
+ (void)commitAnimations;                                                 // starts up any animations when the top level animation is commited

iOS 4中引入了block:

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL

其實(shí)兩者都在做同樣的事,block形式的寫法更為簡潔

CATransaction的+begin和+commit方法在+animateWithDuration:animations:內(nèi)部自動(dòng)調(diào)用,這樣block中所有屬性的改變都會(huì)被事務(wù)所包含,也可以避免開發(fā)者由于對+begin和+commit匹配的失誤造成的風(fēng)險(xiǎn)


行為:

為毛我修改layer的backgroundColor,隱式動(dòng)畫的效果一直是漸變呢,為毛不能是淡入淡出或其他效果呢?這就要看圖層的行為了

圖層行為,實(shí)質(zhì)上是如下幾步:

  • 圖層首先檢測它是否有委托,并且是否實(shí)現(xiàn)CALayerDelegate協(xié)議指定的-actionForLayer:forKey:方法,如果有,直接調(diào)用并返回結(jié)果
  • 如果沒有委托,或者委托沒有實(shí)現(xiàn)-actionForLayer:forKey:方法,圖層接著檢查包含屬性名稱對應(yīng)行為映射的actions字典
  • 如果actions字典沒有包含對應(yīng)的屬性,那么圖層接著在它的style字典接著搜索屬性名
  • 最后,如果在style里面也找不到對應(yīng)的行為,那么圖層將會(huì)直接調(diào)用定義了每個(gè)屬性的標(biāo)準(zhǔn)行為的-defaultActionForKey:方法

我們一步一步試一下:

  1. 圖層首先檢測它是否有委托,并且是否實(shí)現(xiàn)CALayerDelegate協(xié)議指定的-actionForLayer:forKey:方法,如果有,直接調(diào)用并返回結(jié)果
-(void)viewDidLoad{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
    layer = [CALayer layer];
    layer.backgroundColor = [UIColor redColor].CGColor;
    layer.bounds = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
    layer.position = self.view.layer.position;
    layer.delegate = self;
    [self.view.layer addSublayer:layer];
}
-(id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event{
    NSLog(@"event is : %@",event);
    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromLeft;
    return transition;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    [CATransaction begin];
    [CATransaction setAnimationDuration:5.0f];
    [CATransaction setCompletionBlock:^{
        NSLog(@"completion");
    }];
    layer.backgroundColor = [UIColor blueColor].CGColor;
    [CATransaction commit];
}

-actionForLayer:forKey:需要返回一個(gè)遵守<CAAction>協(xié)議的對象,這個(gè)對象定義了圖層的行為
CATransition遵守<CAAction>協(xié)議,可以用于創(chuàng)建過渡動(dòng)畫,并返回給圖層
CATransition是另一個(gè)CAAnimation的子類,和別的子類不同,CATransition有一個(gè)type和subtype來標(biāo)識(shí)變換效果,type屬性是一個(gè)NSString類型,可以被設(shè)置成如下類型:

/* Common transition types. */
CA_EXTERN NSString * const kCATransitionFade
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionMoveIn
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionPush
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionReveal
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);

subtype用來控制動(dòng)畫方向,提供了如下四種類型:

/* Common transition subtypes. */
CA_EXTERN NSString * const kCATransitionFromRight
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionFromLeft
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionFromTop
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionFromBottom
    CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
running.gif
  1. 如果沒有委托,或者委托沒有實(shí)現(xiàn)-actionForLayer:forKey:方法,圖層接著檢查包含屬性名稱對應(yīng)行為映射的actions字典
-(void)viewDidLoad{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
    layer = [CALayer layer];
    layer.backgroundColor = [UIColor redColor].CGColor;
    layer.bounds = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
    layer.position = self.view.layer.position;
    layer.delegate = self;
    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromRight;
    layer.actions = @{@"backgroundColor":transition};
    [self.view.layer addSublayer:layer];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    [CATransaction begin];
    [CATransaction setAnimationDuration:5.0f];
    [CATransaction setCompletionBlock:^{
        NSLog(@"completion");
    }];
    layer.backgroundColor = [UIColor blueColor].CGColor;
    [CATransaction commit];
}
running.gif
  1. 如果actions字典沒有包含對應(yīng)的屬性,那么圖層接著在它的style字典接著搜索屬性名
layer.style = @{@"backgroundColor":transition};

當(dāng)我給layer的style賦值的時(shí)候,卻并沒有效果,不知道為什么了,愿知道的大神留言教我??


呈現(xiàn)圖層

當(dāng)你改變一個(gè)圖層的屬性,屬性值的確是立刻更新的(如果你讀取它的數(shù)據(jù),你會(huì)發(fā)現(xiàn)它的值在你設(shè)置它的那一刻就已經(jīng)生效了),但是屏幕上并沒有馬上發(fā)生改變。這是因?yàn)槟阍O(shè)置的屬性并沒有直接調(diào)整圖層的外觀,相反,他只是定義了圖層動(dòng)畫結(jié)束之后將要變化的外觀

如果你想讀取正在動(dòng)畫中的圖層的當(dāng)前屬性值,得用這個(gè)

/* Returns a copy of the layer containing all properties as they were
 * at the start of the current transaction, with any active animations
 * applied. This gives a close approximation to the version of the layer
 * that is currently displayed. Returns nil if the layer has not yet
 * been committed.
 *
 * The effect of attempting to modify the returned layer in any way is
 * undefined.
 *
 * The `sublayers', `mask' and `superlayer' properties of the returned
 * layer return the presentation versions of these properties. This
 * carries through to read-only layer methods. E.g., calling -hitTest:
 * on the result of the -presentationLayer will query the presentation
 * values of the layer tree. */

- (nullable instancetype)presentationLayer;

舉個(gè)栗子:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
    layer = [CALayer layer];
    layer.backgroundColor = [UIColor redColor].CGColor;
    layer.bounds = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
    layer.position = self.view.layer.position;
    layer.delegate = self;
    
    [self.view.layer addSublayer:layer];
}

-(void)timerAction{
    NSLog(@"presentationLayer.position = %@\tlayer.position = %@",NSStringFromCGPoint(layer.presentationLayer.position),NSStringFromCGPoint(layer.position));
}

//-(id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event{
//    NSLog(@"event is : %@",event);
//    CATransition *transition = [CATransition animation];
//    transition.type = kCATransitionPush;
//    transition.subtype = kCATransitionFromLeft;
//    return transition;
//}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:.5f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];

    [CATransaction begin];
    [CATransaction setAnimationDuration:5.0f];
    [CATransaction setCompletionBlock:^{
        NSLog(@"completion");
        [timer invalidate];
    }];
    layer.position = CGPointMake(0.0f, 0.0f);
    [CATransaction commit];
    
}

輸出:

屏幕快照 2017-03-09 下午4.09.50.png

但是當(dāng)我改變layer的默認(rèn)行為的時(shí)候(就是注釋的那部分),presentationLayer就不能獲取到正確的值了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你可以看...
    F麥子閱讀 5,258評論 5 13
  • 按照我的意思去做,而不是我說的。 -- 埃德娜,辛普森 我們在第一部分討論了Core Animation除了動(dòng)畫之...
    雪_晟閱讀 945評論 0 3
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,686評論 6 30
  • 顯式動(dòng)畫 顯式動(dòng)畫,它能夠?qū)σ恍傩宰鲋付ǖ淖远x動(dòng)畫,或者創(chuàng)建非線性動(dòng)畫,比如沿著任意一條曲線移動(dòng)。 屬性動(dòng)畫 ...
    清風(fēng)沐沐閱讀 2,091評論 1 5
  • 前言 本文只要描述了iOS中的Core Animation(核心動(dòng)畫:隱式動(dòng)畫、顯示動(dòng)畫)、貝塞爾曲線、UIVie...
    GitHubPorter閱讀 3,735評論 7 11

友情鏈接更多精彩內(nèi)容