ホームページ  >  記事  >  ウェブフロントエンド  >  [iOSアニメーション] - CALayerでアニメーションを表示します レイヤーtreeのアニメーション_html/css_WEB - ITnose

[iOSアニメーション] - CALayerでアニメーションを表示します レイヤーtreeのアニメーション_html/css_WEB - ITnose

WBOY
WBOYオリジナル
2016-06-24 11:36:301040ブラウズ

レイヤー ツリーのアニメーション

CATransition は、指定されたレイヤー プロパティには作用しません。つまり、行が追加されたときなど、何が変更されたのか正確に分からない場合でも、レイヤーをアニメーション化できます。または削除された場合は、UIViewController 内のビュー階層を知らなくても、直接スムーズに更新したり、2 つの異なるインスタンス間の遷移をアニメーション化したりできます。

これらの例は、レイヤーのプロパティだけでなく、レイヤー ツリー全体の変更も含まれるため、前に説明したものとは完全に異なります。このアニメーションのレイヤーの削除中に、階層関係を手動で追加または移動します。

ここでは、トランジション アニメーションが発生したときに CATransition によって追加されたレイヤーがツリー構造内で削除されないようにするために、ちょっとしたトリックが使用されています。そうでない場合、CATransition はレイヤーと一緒に削除されます。一般に、影響を受けるレイヤーのスーパーレイヤーにアニメーションを追加するだけで済みます。

リスト 8.2 では、UITabBarController がタブを切り替えるときにフェード アニメーションを追加する方法を示します。ここでは、デフォルトのタブ アプリケーション テンプレートを作成し、UITabBarControllerDelegate の -tabBarController:didSelectViewController: メソッドを使用して遷移アニメーションを適用します。ラベルが置き換えられたときにアニメーションが削除されないように、アニメーションを UITabBarController のビュー レイヤに追加します。

リスト 8.12 UITabBarController のアニメーション化

#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

カスタムアニメーション

トランジションは、スムーズにアニメーション化するのが難しいプロパティにとって強力なツールであることを確認しました。 CATransition提供ですがアニメーションが少なすぎます種類。

さらに奇妙なのは、Apple が UIView +transitionFromView:toView:duration:options:completion: メソッドと +transitionWithView:duration:options:animations: メソッドを通じて、コア アニメーションのトランジション機能を提供していることです。ただし、ここで使用できる遷移オプションは、CATransition の type 属性によって提供される定数とはまったく異なります。 UIView 遷移メソッドのオプション パラメーターは次の定数で指定できます:

UIViewAnimationOptionTransitionFlipFromLeft UIViewAnimationOptionTransitionFlipFromRightUIViewAnimationOptionTransitionCurlUp UIViewAnimationOptionTransitionCurlDownUIViewAnimationOptionTransitionCrossDissolve UIViewAnimationOptionTransitionFlipFromTop UIViewAnimationOptionTransitionFlipFromBottom

UIViewAnimationOptionTransitionCrossDissolve を除き、残りの値は CATransition タイプとは関係ありません。前の例の修正バージョンを使用してこれをテストできます (リスト 8.13 を参照)。

清单8.13 UIKit 提供の方法を使って过渡アニメーション画

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIImageView *imageView;@property (nonatomic, copy) NSArray *images; @end @implementation ViewController - (void)viewDidLoad{    [super viewDidLoad]; //set up images self.images = @[[UIImage imageNamed:@"Anchor.png"],                    [UIImage imageNamed:@"Cone.png"],                    [UIImage imageNamed:@"Igloo.png"],                    [UIImage imageNamed:@"Spaceship.png"]]; - (IBAction)switchImage{    [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];} @end

文档暗示过在iOS5(带来了Core Image)フレーム)その後、CATransition のフィルター プロパティを介して、CIFilter を使用できるようになります。他のトランジション効果を作成します。ただし、iOS6まではこれができませんでした。 CATransition で Core Image のフィルタを使用しようとしても、まったく効果がありません (ただし、Mac OS では可能です。ドキュメントでこれを表現したいのかもしれません)。

したがって、達成したい効果に応じて、CATransition を使用するか、UIView の遷移メソッドを使用するかを考慮するだけで済みます。 iOS システムの次のバージョンが CATransition を通じて Core Image のトランジション フィルタ効果をサポートできることを願っています (おそらく新しい方法もあるでしょう)。

ただし、これは iOS でカスタムトランジション効果を実現できないという意味ではありません。それは、追加の作業が必要であることを意味します。前述したように、トランジション アニメーションの基本原理は、元のレイヤーの外観のスクリーンショットを取得し、レイヤーの変更後にスクリーンショットの効果にスムーズに移行するアニメーションを追加することです。レイヤーのスクリーンショットを撮る方法がわかっていれば、CATransition や UIKit の遷移メソッドの代わりにプロパティ アニメーションを使用してアニメーションを実装できます。

レイヤーのスクリーンショットを撮るのは非常に簡単であることがわかりました。 CALayer には -renderInContext: メソッドがあり、現在のコンテンツを Core Graphics のコンテキストに描画することでその画像をキャプチャし、別のビューに表示できます。このスクリーンショット ビューを元のビューの上に配置すると、実際のビューに対するすべての変更をマスクして、単純なトランジション効果を再作成できます。

リスト 8.14 は、基本的な実装を示しています。現在のビュー状態のスクリーンショットを取得し、元のビューの背景色を変更するときにスクリーンショットをすばやく回転してフェードアウトします。図 8.5 は、カスタム トランジション効果を示しています。

物事を簡単にするために、UIView -animateWithDuration:completion: メソッドを使用して実装します。同じ効果は CABasicAnimation でも実現できますが、その場合はレイヤーの変換プロパティと不透明度プロパティに対して個別のアニメーションを作成する必要があります。その後、アニメーションが終了すると、ユーザーは CAAnimationDelegate の画面から coverView を削除します。

リスト 8.14 renderInContext: を使用してカスタム トランジション エフェクトを作成する

@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];    }];} @end

図 8.5 renderInContext: を使用してカスタム トランジション エフェクトを作成する

这里有个警告: -renderInContext: 捕获了图层的图片和子图层,但是不能对子图层正确地处理变换效果,而且对视频和OpenGL内容也不起作用。但是用CATransition,或者用私有的截屏方式就没有这个限制了。

在动画过程中取消动画

之前提到过,你可以用 -addAnimation:forKey: 方法中的key参数来在添加动画之后检索一个动画,使用如下方法:

- (CAAnimation *)animationForKey:(NSString *)key;

 

但并不支持在动画运行过程中修改动画,所以这个方法主要用来检测动画的属性,或者判断它是否被添加到当前图层中。

为了终止一个指定的动画,你可以用如下方法把它从图层移除掉:

- (void)removeAnimationForKey:(NSString *)key;

 

或者移除所有动画:

- (void)removeAllAnimations;

 

动画一旦被移除,图层的外观就立刻更新到当前的模型图层的值。一般说来,动画在结束之后被自动移除,除非设置removedOnCompletion为NO,如果你设置动画在结束之后不被自动移除,那么当它不需要的时候你要手动移除它;否则它会一直存在于内存中,直到图层被销毁。

我们来扩展之前旋转飞船的示例,这里添加一个按钮来停止或者启动动画。这一次我们用一个非nil的值作为动画的键,以便之后可以移除它。 -animationDidStop:finished: 方法中的flag参数表明了动画是自然结束还是被打断,我们可以在控制台打印出来。如果你用停止按钮来终止动画,它会打印NO,如果允许它完成,它会打印YES。

清单8.15是更新后的示例代码,图8.6显示了结果。

清单8.15 开始和停止一个动画

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *containerView;@property (nonatomic, strong) CALayer *shipLayer; @end @implementation ViewController - (void)viewDidLoad{    [super viewDidLoad]; //add the ship self.shipLayer = [CALayer layer];    self.shipLayer.frame = CGRectMake(0, 0, 128, 128);    self.shipLayer.position = CGPointMake(150, 150);    self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;    [self.containerView.layer addSublayer:self.shipLayer];} - (IBAction)start{ //animate the ship rotation CABasicAnimation *animation = [CABasicAnimation animation];    animation.keyPath = @"transform.rotation";    animation.duration = 2.0;    animation.byValue = @(M_PI * 2);    animation.delegate = self;    [self.shipLayer addAnimation:animation forKey:@"rotateAnimation"];} - (IBAction)stop{    [self.shipLayer removeAnimationForKey:@"rotateAnimation"];} - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ //log that the animation stopped NSLog(@"The animation stopped (finished: %@)", flag? @"YES": @"NO");} @end

 

图8.6 通过开始和停止按钮控制的旋转动画

总结

这一章中,我们涉及了属性动画(你可以对单独的图层属性动画有更加具体的控制),动画组(把多个属性动画组合成一个独立单元)以及过度(影响整个图层,可以用来对图层的任何内容做任何类型的动画,包括子图层的添加和移除)。

在第九章中,我们继续学习CAMediaTiming协议,来看一看Core Animation是怎样处理逝去的时间。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。