Core Animationの話  Part.1
Upcoming SlideShare
Loading in...5
×
 

Core Animationの話 Part.1

on

  • 1,330 views

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

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

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

Statistics

Views

Total Views
1,330
Views on SlideShare
1,143
Embed Views
187

Actions

Likes
1
Downloads
4
Comments
0

2 Embeds 187

http://cocoa.hatenablog.com 185
https://www.google.co.jp 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Core Animationの話  Part.1 Core Animationの話 Part.1 Presentation Transcript

  • Core Animationの話 Part.1 初めによくある問題 2012.05.19 ふじしげ ゆういち @nakiwo
  • • ふじしげ ゆういち • @nakiwo • 株式会社フィードテイラー http://feedtailor.jp/ Book+ そら案内 SYNCNEL
  • • ふじしげ ゆういち • @nakiwo • http://www.nakiwo.com/ 洞窟物語 めがね (Mac AppStore)
  • 今日のテーマ •Core Animation •最初にはまりがちな問題 『アニメーション終了後表示が戻る』 •結論は簡単。過程が複雑 •iOS
  • 今日のサンプル https://github.com/nakiwo/CoreAnimationSample1
  • Core Animation •矩形の高速表示+アニメーションのため の仕組み (Open GL のラッパー) •OS X v10.5で導入 •iOSでは最初からある •CALayer/CAAnimation
  • 何が嬉しい? • Core Animationでしかできない事がある • UIView/NSViewのアニメーション機構で 済むならそれが一番楽
  • •2.5Dアニメーション (平面を3D配置) •繰り返しアニメーション •キーフレームアニメーション • CAReplicatorLayer, CAEmitterLayer, CAGradientLayer, AVPlayerLayer, AVCaptureVideoPreviewLayer etc..
  • •NSViewとCALayerはあまりうまく統 合されていない •layer-backed mode •layer-hosting mode NSViewとの統合 NSView - (void)setWantsLayer:(BOOL)flag
  • •UIViewはCALayerのラッパー •UIViewとCALayerは完全に統合されて いる(片方のプロパティを変えると相互 に反映される ※若干名前違い有り) UIViewとの統合 UIView @property(nonatomic, readonly, retain) CALayer *layer
  • #import <QuartzCore/QuartzCore.h> UIView *view; ... CALayer *layer = [CALayer layer]; ... [view.layer addSublayer:layer];
  • 本題・よくある問題 •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"];
  • デモ ※ Keynoteを中断する時は[H]を押す
  • よく見かける解決策 •微妙に気持ち悪い 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"];
  • 何が問題?
  • CALayer •Core Animationレンダリングシステム が表示する内容を表すデータモデル •NSView/UIViewと違い、イベントハン ドリングの仕組みを持っていない (表示専任)
  • animatable •CALayerのプロパティのうち、アニ メーション可能な物はドキュメントに animatable の記載がある position Specifies the receiver’s position in the superlayer’s coordinate system. Animatable. @property CGPoint position
  • 暗黙的アニメーション •implicit animation •animatableなプロパティを変更すると 勝手にアニメーション発動 (hidden、addSubLayer, removeFromSuperLayer 等でも発動) _testLayer.position = CGPointMake(x, y);
  • •暗黙的アニメーションは現在のトラン ザクション設定に基づいて発動する •トランザクションを明示しない場合、 デフォルトのトランザクションが適用 される [CATransaction begin]; [CATransaction setAnimationDuration:2]; _testLayer.position = _endPoint; [CATransaction commit];
  • CAAnimation • 明示的アニメーション(explicit animation) • アニメーション=時間と共に変化するプロパ ティ • CALayerにkey/valueで関連づける (明示的アニメーション) • CALayerのプロパティを一時的に上書きする • 細かい設定が可能
  • CABasicAnimation CAPropertyAnimation CAAnimation <CAMediaTiming, CAAction> CAKeyframeAnimation fromValue, toValue, byValue keyPath values, keyTimes
  • 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で関連
  • 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 は無関係
  • CALayer opacity=0.0 レイヤーツリー CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  • レイヤーツリー 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
  • CAAction •暗黙アニメーション発動時に実行され るアニメーション CAAnimation : NSObject <CAAction> CALayer - (id<CAAction>)actionForKey:(NSString *)event;
  • 暗黙アニメーションとアクション • Layerのプロパティ X を更新する • [layer actionForKey:@ X ]で取り出された Action(=Animation)が、Layerに追加され る • Layerのプロパティ値が実際に更新される _testLayer.X = n; CAAnimation <CAAction> CALayer key=”X”
  • 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を設定
  • 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”
  • 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を設定
  • 本題・よくある問題 •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"];
  • CALayer opacity=0.0 CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  • 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
  • CALayer opacity=0.0 CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  • よく見る解決策 •微妙に気持ち悪さが残る 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"];
  • CALayer opacity=0.0 CALayer opacity=0.0 opaticity=0.0 opaticity=0.0 Layer Tree Presentation Tree Render Tree (private) layer.presentationLayer
  • 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
  • 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
  • 解決策 •先にLayerの値を更新しておく
  • [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];
  • [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];
  • [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];
  • // 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しか無い
  • UIViewのLayer •UIView.layerは暗黙アニメーション(デ フォルトアクション)が無効になってい る //[CATransaction begin]; // 不要 //[CATransaction setDisableActions:YES]; // 不要 view.layer.position = _endPoint; //[CATransaction commit]; // 不要 [view.layer addAnimation:anim forKey:@"hoge"];
  • 参考資料 • Core Animation Programming Guide