Core Animationの話 Part.1

2,726 views

Published on

Core Animation でアニメーション終了後位置が戻る問題の話。

第44回 Cocoa勉強会関西の発表資料。

Published in: Technology
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,726
On SlideShare
0
From Embeds
0
Number of Embeds
528
Actions
Shares
0
Downloads
7
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

Core Animationの話 Part.1

  1. 1. Core Animationの話 Part.1 初めによくある問題 2012.05.19 ふじしげ ゆういち @nakiwo
  2. 2. • ふじしげ ゆういち • @nakiwo • 株式会社フィードテイラー http://feedtailor.jp/ Book+ そら案内 SYNCNEL
  3. 3. • ふじしげ ゆういち • @nakiwo • http://www.nakiwo.com/ 洞窟物語 めがね (Mac AppStore)
  4. 4. 今日のテーマ •Core Animation •最初にはまりがちな問題 『アニメーション終了後表示が戻る』 •結論は簡単。過程が複雑 •iOS
  5. 5. 今日のサンプル https://github.com/nakiwo/CoreAnimationSample1
  6. 6. Core Animation •矩形の高速表示+アニメーションのため の仕組み (Open GL のラッパー) •OS X v10.5で導入 •iOSでは最初からある •CALayer/CAAnimation
  7. 7. 何が嬉しい? • Core Animationでしかできない事がある • UIView/NSViewのアニメーション機構で 済むならそれが一番楽
  8. 8. •2.5Dアニメーション (平面を3D配置) •繰り返しアニメーション •キーフレームアニメーション • CAReplicatorLayer, CAEmitterLayer, CAGradientLayer, AVPlayerLayer, AVCaptureVideoPreviewLayer etc..
  9. 9. •NSViewとCALayerはあまりうまく統 合されていない •layer-backed mode •layer-hosting mode NSViewとの統合 NSView - (void)setWantsLayer:(BOOL)flag
  10. 10. •UIViewはCALayerのラッパー •UIViewとCALayerは完全に統合されて いる(片方のプロパティを変えると相互 に反映される ※若干名前違い有り) UIViewとの統合 UIView @property(nonatomic, readonly, retain) CALayer *layer
  11. 11. #import <QuartzCore/QuartzCore.h> UIView *view; ... CALayer *layer = [CALayer layer]; ... [view.layer addSublayer:layer];
  12. 12. 本題・よくある問題 •CABasicAnimationをLayerに追加す るとアニメーションした後元の表示に 戻る CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 0.5; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; [_testLayer addAnimation:anim forKey:@"hoge"];
  13. 13. デモ ※ Keynoteを中断する時は[H]を押す
  14. 14. よく見かける解決策 •微妙に気持ち悪い CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 0.5; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; // アニメーションが終了しても自動削除しない // 終了後はtoValueをキープ anim.removedOnCompletion = NO; anim.fillMode = kCAFillModeForwards; [_testLayer addAnimation:anim forKey:@"hoge"];
  15. 15. 何が問題?
  16. 16. CALayer •Core Animationレンダリングシステム が表示する内容を表すデータモデル •NSView/UIViewと違い、イベントハン ドリングの仕組みを持っていない (表示専任)
  17. 17. animatable •CALayerのプロパティのうち、アニ メーション可能な物はドキュメントに animatable の記載がある position Specifies the receiver’s position in the superlayer’s coordinate system. Animatable. @property CGPoint position
  18. 18. 暗黙的アニメーション •implicit animation •animatableなプロパティを変更すると 勝手にアニメーション発動 (hidden、addSubLayer, removeFromSuperLayer 等でも発動) _testLayer.position = CGPointMake(x, y);
  19. 19. •暗黙的アニメーションは現在のトラン ザクション設定に基づいて発動する •トランザクションを明示しない場合、 デフォルトのトランザクションが適用 される [CATransaction begin]; [CATransaction setAnimationDuration:2]; _testLayer.position = _endPoint; [CATransaction commit];
  20. 20. CAAnimation • 明示的アニメーション(explicit animation) • アニメーション=時間と共に変化するプロパ ティ • CALayerにkey/valueで関連づける (明示的アニメーション) • CALayerのプロパティを一時的に上書きする • 細かい設定が可能
  21. 21. CABasicAnimation CAPropertyAnimation CAAnimation <CAMediaTiming, CAAction> CAKeyframeAnimation fromValue, toValue, byValue keyPath values, keyTimes
  22. 22. CABasicAnimation duration=1.0 keypath=“position” fromValue=(10,10) toValue= (20,20) CALayer CABasicAnimation duration=1.0 keypath=“opacity” fromValue=0.0 toValue=1.0 - (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key; - (void)removeAnimationForKey:(NSString *)key; - (void)removeAllAnimations; - (NSArray *)animationKeys; - (CAAnimation *)animationForKey:(NSString *)key; key=”hoge” key=”fuga” LayerとAnimationはkey-valueで関連
  23. 23. CABasicAnimation duration=1.0 keypath=“position” fromValue=(10,10) toValue= (20,20) CALayer CABasicAnimation duration=1.0 keypath=“opacity” fromValue=0.0 toValue=1.0 key=”hoge” key=”fuga” LayerとAnimationはkey-valueで関連 layer->animationのkeyと、 animationのkeypath は無関係
  24. 24. CALayer opacity=0.0 レイヤーツリー CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  25. 25. レイヤーツリー CALayer opacity=0.0 CABasicAnimation duration=1.0 keypath=“opacity” fromValue=0.0 toValue=1.0 opaticity=0.0 opaticity=0.0->1.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer opaticity=0.0->1.0
  26. 26. CAAction •暗黙アニメーション発動時に実行され るアニメーション CAAnimation : NSObject <CAAction> CALayer - (id<CAAction>)actionForKey:(NSString *)event;
  27. 27. 暗黙アニメーションとアクション • Layerのプロパティ X を更新する • [layer actionForKey:@ X ]で取り出された Action(=Animation)が、Layerに追加され る • Layerのプロパティ値が実際に更新される _testLayer.X = n; CAAnimation <CAAction> CALayer key=”X”
  28. 28. CALayer opacity=0.0 CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer layer.opaticity=0の状態で layer.opaticity=1を設定
  29. 29. CALayer opacity=1.0 CABasicAnimation duration=1.0 keypath=“opacity” fromValue=0.0 toValue=1.0 opaticity=1.0 opaticity=0.0->1.0 opaticity=0.0->1.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer layer.opaticity=0の状態で layer.opaticity=1を設定 key= ”opacity”
  30. 30. CALayer opacity=1.0 CALayer opacity=1.0 opaticity=1.0 opaticity=1.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer layer.opaticity=0の状態で layer.opaticity=1を設定
  31. 31. 本題・よくある問題 •CABasicAnimationをLayerに追加す るとアニメーションした後元の表示に 戻る CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 0.5; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; [_testLayer addAnimation:anim forKey:@"hoge"];
  32. 32. CALayer opacity=0.0 CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  33. 33. CALayer opacity=0.0 CABasicAnimation duration=1.0 keypath=“opacity” fromValue=0.0 toValue=1.0 opaticity=0.0 opaticity=0.0->1.0 opaticity=0.0->1.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  34. 34. CALayer opacity=0.0 CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  35. 35. よく見る解決策 •微妙に気持ち悪さが残る CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 0.5; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; // アニメーションが終了しても自動削除しない // 終了後はtoValueをキープ anim.removedOnCompletion = NO; anim.fillMode = kCAFillModeForwards; [_testLayer addAnimation:anim forKey:@"hoge"];
  36. 36. CALayer opacity=0.0 CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  37. 37. CALayer opacity=0.0 CABasicAnimation duration=1.0 keypath=“opacity” fromValue=0.0 toValue=1.0 opaticity=0.0 opaticity=0.0->1.0 opaticity=0.0->1.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  38. 38. CALayer opacity=0.0 CABasicAnimation duration=1.0 keypath=“opacity” fromValue=0.0 toValue=1.0 opaticity=0.0 opaticity=1.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer opaticity=1.0
  39. 39. 解決策 •先にLayerの値を更新しておく
  40. 40. [CATransaction begin]; // 暗黙トランザクションのdurationを長めに設定(確認用) [CATransaction setAnimationDuration:4]; // animations追加 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 0.3; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; // モデルの値も更新しておく // しかしこの方法だとimplicitアニメーションも同時に走ってしまう! // 同じkeyPathに対するアニメーションが2つ以上ある場合、どちらが勝つかは不定? // 登録された順番により結果が異なる様子 _testLayer.position = _endPoint; // ここで暗黙アニメーション発動 [self showAnimations]; // positionアニメーションが登録されている事がわかる [_testLayer addAnimation:anim forKey:@"hoge"]; // 適当な名前のキーで追加 [self showAnimations]; // hoge/positionの2アニメーションが登録されている事がわかる [CATransaction commit];
  41. 41. [CATransaction begin]; // 暗黙トランザクションのdurationを長めに設定(確認用) [CATransaction setAnimationDuration:4]; // animations追加 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 0.3; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; // モデルの値も更新しておく // しかしこの方法だとimplicitアニメーションも同時に走ってしまう! // 同じkeyPathに対するアニメーションが2つ以上ある場合、どちらが勝つかは不定? // 登録された順番により結果が異なる様子 _testLayer.position = _endPoint; // ここで暗黙アニメーション発動 [self showAnimations]; // positionアニメーションが登録されている事がわかる [_testLayer addAnimation:anim forKey:@"hoge"]; // 適当な名前のキーで追加 [self showAnimations]; // hoge/positionの2アニメーションが登録されている事がわかる [CATransaction commit];
  42. 42. [CATransaction begin]; // 暗黙トランザクションのdurationを長めに設定(explicit3との対比確認のため) [CATransaction setAnimationDuration:4]; NSLog(@"current transaction animationDuration : %f", [CATransaction animationDuration]); // animations追加 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 1; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; // おすすめ解決策その1 // モデルの値も更新しておく。 _testLayer.position = _endPoint; // デフォルトアクションが発動 [self showAnimations]; // positionのみ(デフォルトアクション) // アニメーションを登録する際、元のプロパティ名をキーとして使用する // 同じキーのアニメーションは1つしか登録出来ない。同じ名前があると上書きされる。 // implicitアニメーションのアニメーションと同じキーで上書き [_testLayer addAnimation:anim forKey:@"position"]; [self showAnimations]; // positionのみ(アプリが指定したインスタンス) [CATransaction commit];
  43. 43. // animations追加 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; anim.fromValue = [NSValue valueWithCGPoint:_startPoint]; anim.toValue = [NSValue valueWithCGPoint:_endPoint]; anim.duration = 0.5; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; // おすすめ解決策その2 // モデルの値も更新しておく // デフォルトアクション(=implicitアニメーション)が走らないように設定 [CATransaction begin]; [CATransaction setDisableActions:YES]; _testLayer.position = _endPoint; // Layerアクションが無効になっているのでアニメーションは発動しない [CATransaction commit]; [self showAnimations]; // アニメーション無し [_testLayer addAnimation:anim forKey:@"hoge"]; // 適当な名前のキーで追加 [self showAnimations]; // hogeしか無い
  44. 44. UIViewのLayer •UIView.layerは暗黙アニメーション(デ フォルトアクション)が無効になってい る //[CATransaction begin]; // 不要 //[CATransaction setDisableActions:YES]; // 不要 view.layer.position = _endPoint; //[CATransaction commit]; // 不要 [view.layer addAnimation:anim forKey:@"hoge"];
  45. 45. 参考資料 • Core Animation Programming Guide

×