CoreAnimation手記(二)顯式動(dòng)畫

屬性動(dòng)畫

屬性動(dòng)畫 最用于圖層的某個(gè)單一屬性,并指定了它的一個(gè)目標(biāo)值,或者一連串要做的動(dòng)畫值.
屬性動(dòng)畫分 基礎(chǔ)動(dòng)畫和關(guān)鍵幀動(dòng)畫

基礎(chǔ)動(dòng)畫

最簡(jiǎn)單的形式就是從一個(gè)值改變到另一個(gè)值,這也是CABasicAnimation最主要的功能。

CABasicAnimation是CAPropertyAnimation的一個(gè)子類,而CAPropertyAnimation的父類是CAAnimation

一.第一個(gè)類CABasicAnimation

筆記: CABasicAnimation 的三個(gè)重要屬性 id fromValue id toValue id byValue,為了防止沖突,不能一次性同時(shí)給這三個(gè)值賦值.

有一個(gè)注意的是,設(shè)置動(dòng)畫,過(guò)度到一個(gè)新的顏色,但是動(dòng)畫結(jié)束之后,又立刻變回原來(lái)的顏色.

<code><pre>
Type Object Type Code Example

CGFloat NSNumber id obj = @(float);

CGPoint NSValue id obj = [NSValue valueWithCGPoint:point);

CGSize NSValue id obj = [NSValue valueWithCGSize:size);

CGRect NSValue id obj = [NSValue valueWithCGRect:rect);

CATransform3D NSValue id obj = [NSValue valueWithCATransform3D:transform);

CGImageRef id id obj = (__bridge id)imageRef;

CGColorRef id id obj = (__bridge id)colorRef;
</code></pre>
第一個(gè)解決方案:
在動(dòng)畫開(kāi)始之前或者動(dòng)畫結(jié)束之后。

<code><pre>
CALayer *layer = self.colorLayer.presentationLayer ?:self.colorLayer;

animation.fromValue = (__bridge id)layer.backgroundColor;

[CATransaction begin];

[CATransaction setDisableActions:YES];

self.colorLayer.backgroundColor = color.CGColor;

[CATransaction commit];
</code></pre>

說(shuō)明這里了設(shè)置圖層的顏色屬性,禁止了隱式動(dòng)畫,因?yàn)檫@里的圖層是獨(dú)立的,不是UIVIew中得

<code><pre>
//這里封裝了一個(gè)方法替代 setValue animation to value直接applyBasicAnimation 這樣,動(dòng)畫完了以后,設(shè)置

的屬性變化也會(huì)對(duì)應(yīng)修改 這個(gè)代碼可以復(fù)制過(guò)去
- (void)applyBasicAnimation:(CABasicAnimation *)animation toLayer:(CALayer *)layer{
//set the from value (using presentation layer if available)
animation.fromValue = [layer.presentationLayer ?: layer valueForKeyPath:animation.keyPath];

//update the property in advance //note: this approach will only work if toValue != nil

[CATransaction begin];

[CATransaction setDisableActions:YES];

[layer setValue:animation.toValue forKeyPath:animation.keyPath];

[CATransaction commit];

//apply animation to layer

[layer addAnimation:animation forKey:nil];
}

  - (IBAction)changeColor{ 

//create a new random color

CGFloat red = arc4random() / (CGFloat)INT_MAX; CGFloat green = arc4random() / (CGFloat)INT_MAX;

CGFloat blue = arc4random() / (CGFloat)INT_MAX;

UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];

//create a basic animation

CABasicAnimation *animation = [CABasicAnimation animation];

animation.keyPath = @"backgroundColor";

animation.toValue = (__bridge id)color.CGColor;

//apply animation without snap-back

[self applyBasicAnimation:animation toLayer:self.colorLayer];
}

</code></pre>

說(shuō)明這里 使用keyPath 修改layer的一個(gè)屬性動(dòng)畫,實(shí)際上它是一個(gè)關(guān)鍵路徑(一些用點(diǎn)表示法可以在層級(jí)關(guān)系中指向任意嵌套的對(duì)象),而不僅僅是一個(gè)屬性的名稱,因?yàn)檫@意味著動(dòng)畫不僅可以作用于圖層本身的屬性,而且還包含了它的子成員的屬性,甚至是一些虛擬的屬性(后面會(huì)詳細(xì)解釋)。

第二個(gè)解決方案:

實(shí)現(xiàn)CAAnimationDelegate 協(xié)議中的delegate

- (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag
{
//set the backgroundColor property to match animation toValue
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.colorLayer.backgroundColor = (__bridge CGColorRef)anim.toValue;
[CATransaction commit];
}

注意:使用委托模式而不是一個(gè)完成塊會(huì)帶來(lái)一個(gè)問(wèn)題,就是當(dāng)你有多個(gè)動(dòng)畫的時(shí)候,無(wú)法在在回調(diào)方法中區(qū)分哪個(gè)圖層調(diào)用的。

引用:

不幸的是,即使做了這些,還是有個(gè)問(wèn)題,清單8.4在模擬器上運(yùn)行的很好,但當(dāng)真正跑在iOS設(shè)備上時(shí),我們發(fā)現(xiàn)在-animationDidStop:finished:委托方法調(diào)用之前,指針會(huì)迅速返回到原始值,這個(gè)清單8.3圖層顏色發(fā)生的情況一樣。

問(wèn)題在于回調(diào)方法在動(dòng)畫完成之前已經(jīng)被調(diào)用了,但不能保證這發(fā)生在屬性動(dòng)畫返回初始狀態(tài)之前。這同時(shí)也很好地說(shuō)明了為什么要在真實(shí)的設(shè)備上測(cè)試動(dòng)畫代碼,而不僅僅是模擬器。

我們可以用一個(gè)fillMode屬性來(lái)解決這個(gè)問(wèn)題,下一章會(huì)詳細(xì)說(shuō)明,這里知道在動(dòng)畫之前設(shè)置它比在動(dòng)畫結(jié)束之后更新屬性更加方便。

第二個(gè)類:CAKeyframeAnimation

<code><pre>
@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIView *containerView;

@end

@implementation ViewController

- (void)viewDidLoad

{
[super viewDidLoad];
//create a path

UIBezierPath *bezierPath = [[UIBezierPath alloc] init];

[bezierPath moveToPoint:CGPointMake(0, 150)];

[bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];

//draw the path using a CAShapeLayer

CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.path = bezierPath.CGPath;
pathLayer.fillColor = [UIColor clearColor].CGColor;
pathLayer.strokeColor = [UIColor redColor].CGColor;
pathLayer.lineWidth = 3.0f;
[self.containerView.layer addSublayer:pathLayer];

//add the ship
CALayer *shipLayer = [CALayer layer];
shipLayer.frame = CGRectMake(0, 0, 64, 64);
shipLayer.position = CGPointMake(0, 150);
shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
[self.containerView.layer addSublayer:shipLayer];
//create the keyframe animation
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position";
animation.duration = 4.0;
animation.path = bezierPath.CGPath;
[shipLayer addAnimation:animation forKey:nil];

}

@end

</code></pre>

運(yùn)行示例,你會(huì)發(fā)現(xiàn)飛船的動(dòng)畫有些不太真實(shí),這是因?yàn)楫?dāng)它運(yùn)動(dòng)的時(shí)候永遠(yuǎn)指向右邊,而不是指向曲線切線的方向。你可以調(diào)整它的affineTransform來(lái)對(duì)運(yùn)動(dòng)方向做動(dòng)畫,但很可能和其它的動(dòng)畫沖突。

幸運(yùn)的是,蘋果預(yù)見(jiàn)到了這點(diǎn),并且給CAKeyFrameAnimation添加了一個(gè)rotationMode的屬性。設(shè)置它為常量kCAAnimationRotateAuto(清單8.7),圖層將會(huì)根據(jù)曲線的切線自動(dòng)旋轉(zhuǎn)(圖8.2)。

animation.rotationMode = kCAAnimationRotateAuto;

第三個(gè)類 CATransision

CATransision可以對(duì)圖層任何變化平滑過(guò)渡的事實(shí)使得它成為那些不好做動(dòng)畫的屬性圖層行為的理想候選。蘋果當(dāng)然意識(shí)到了這點(diǎn),并且當(dāng)設(shè)置了CALayer的content屬性的時(shí)候,CATransition的確是默認(rèn)的行為。但是對(duì)于視圖關(guān)聯(lián)的圖層,或者是其他隱式動(dòng)畫的行為,這個(gè)特性依然是被禁用的,但是對(duì)于你自己創(chuàng)建的圖層,這意味著對(duì)圖層contents圖片做的改動(dòng)都會(huì)自動(dòng)附上淡入淡出的動(dòng)畫。

這段翻譯的讓我真的是很費(fèi)解.在這里順便說(shuō)明下:

CATransision 可以對(duì)圖層上發(fā)生的任何變化,(屬性或者內(nèi)容大小),都可以添加一個(gè)平滑過(guò)渡的動(dòng)畫.CATransition的動(dòng)畫是默認(rèn)的隱式動(dòng)畫.

過(guò)渡動(dòng)畫和之前的屬性動(dòng)畫或者動(dòng)畫組添加到圖層上的方式一致,都是通過(guò)-addAnimation:forKey:方法。但是和屬性動(dòng)畫不同的是,對(duì)指定的圖層一次只能使用一次CATransition,因此,無(wú)論你對(duì)動(dòng)畫的鍵設(shè)置什么值,過(guò)渡動(dòng)畫都會(huì)對(duì)它的鍵設(shè)置成“transition”,也就是常量kCATransition。

過(guò)渡動(dòng)畫和屬性動(dòng)畫的區(qū)別,兩個(gè)動(dòng)畫的添加方式一直,不過(guò)一個(gè)是默認(rèn)的值,(transition),一個(gè)可以自定義.

一段神奇的代碼

<code><pre>

import "AppDelegate.h"

import "FirstViewController.h"

import "SecondViewController.h"

import <QuartzCore/QuartzCore.h>

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];

UIViewController *viewController1 = [[FirstViewController alloc] init];
UIViewController *viewController2 = [[SecondViewController alloc] init];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = @[viewController1, viewController2];
self.tabBarController.delegate = self;
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;

}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{

 //set up crossfade transition
CATransition *transition = [CATransition animation];
transition.type = kCATransitionFade;
//apply transition to tab bar controller's view
[self.tabBarController.view.layer addAnimation:transition forKey:nil];

}
@end

</code></pre>

UIVIew提供的過(guò)渡動(dòng)畫函數(shù)

[UIView transitionWithView:self.imageView duration:1.0
                   options:UIViewAnimationOptionTransitionFlipFromLeft
                animations:^{
                    //cycle to next image
                    UIImage *currentImage = self.imageView.image;
                    NSUInteger index = [self.images indexOfObject:currentImage];
                    index = (index + 1) % [self.images count];
                    self.imageView.image = self.images[index];
                }
                completion:NULL];

一個(gè)自定義過(guò)渡動(dòng)畫的代碼

<code><pre>
@implementation ViewController
- (IBAction)performTransition
{

//preserve the current view snapshot
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *coverImage = UIGraphicsGetImageFromCurrentImageContext();
//insert snapshot view in front of this one
UIView *coverView = [[UIImageView alloc] initWithImage:coverImage];
coverView.frame = self.view.bounds;
[self.view addSubview:coverView];
//update the view (we'll simply randomize the layer background color)
CGFloat red = arc4random() / (CGFloat)INT_MAX;
CGFloat green = arc4random() / (CGFloat)INT_MAX;
CGFloat blue = arc4random() / (CGFloat)INT_MAX;
self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
//perform animation (anything you like)
[UIView animateWithDuration:1.0 animations:^{
    //scale, rotate and fade the view
    CGAffineTransform transform = CGAffineTransformMakeScale(0.01, 0.01);
    transform = CGAffineTransformRotate(transform, M_PI_2);
    coverView.transform = transform;
    coverView.alpha = 0.0;
} completion:^(BOOL finished) {
    //remove the cover view now we're finished with it
    [coverView removeFromSuperview];
}];

}

</code></pre>

在動(dòng)畫過(guò)程中取消動(dòng)畫

添加動(dòng)畫
- (CAAnimation *)animationForKey:(NSString *)key;

刪除動(dòng)畫
- (void)removeAnimationForKey:(NSString *)key;

或者移除所有動(dòng)畫:

 - (void)removeAllAnimations;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過(guò)程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,573評(píng)論 6 30
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過(guò)程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你可以看...
    F麥子閱讀 5,147評(píng)論 5 13
  • 顯式動(dòng)畫 顯式動(dòng)畫,它能夠?qū)σ恍傩宰鲋付ǖ淖远x動(dòng)畫,或者創(chuàng)建非線性動(dòng)畫,比如沿著任意一條曲線移動(dòng)。 屬性動(dòng)畫 ...
    清風(fēng)沐沐閱讀 1,981評(píng)論 1 5
  • 本文轉(zhuǎn)載自:http://www.cocoachina.com/ios/20150105/10812.html 為...
    idiot_lin閱讀 1,301評(píng)論 0 1
  • Core Animation Core Animation,中文翻譯為核心動(dòng)畫,它是一組非常強(qiáng)大的動(dòng)畫處理API,...
    45b645c5912e閱讀 3,071評(píng)論 0 21