NSViewAnimationにcompletionを付ける | HMDT Blog

NSViewAnimationにcompletionを付ける


最近は、iOSプログラミングとOS Xプログラミングが半々の日々です。

OS XのApp Kitでアニメーションをしようとすると、パッと思いつくのはCore Animationフレームワークです。iOSでもおなじみの、CALayerを使ってアニメーションします。Layer-backedアニメーションってやつですね。

このCALayerによるアニメーションは、パフォーマンスもよく、様々なエフェクトもかけられるし、サポートクラスもたくさんあって、とても便利なんですけど、アニメーションさせてももとのビューが動かない、という特徴があります。見せかけだけなんですね。なので、アニメーション終了後にビューのframeを設定し直したりします。

でも、アニメーションの種類によっては、frameを動かす事が重要なものがあります。たとえば、テキストビューのアニメーションです。テキストビューの大きさが変わるアニメーションの場合、その動きに合わせて内部のテキストの配置も変わってほしいですね。これをCALayerでやろうとすると、単純にテキストが拡大/縮小するだけになってしまいます。アニメーションのステップごとに、テキストビューを毎回redrawしてやらないといけないんですよ。

そこで登場するのが、NSViewAnimation。App Kitのアニメーション周りで最初に登場した古いクラスです。こいつは、ビューのframeの大きさを変えてくれます。たぶん、タイマー回してframeの値を順々に変えているだけの、単純なものです。パフォーマンスはよくないですが、求めに応じて使い分けます。

でも、古いクラスなので、あんまり使い勝手がよくないです。いちばん面倒なのが、アニメーションの終了通知がdelegateなこと。最近はブロック記法にすっかり慣れてしまったので、completionブロックを呼び出してほしいところです。

ということで、そこだけ拡張してみました。NSViewAnimationのサブクラスとして、HMViewAnimationというのを作り、アニメーションが終わったらcompletionを呼び出すanimateWIthAnimations:duration:completion:というメソッドを追加してみました。

宣言はこんな感じ。

typedef void (^HMViewAnimationCompletion)(void);

@interface HMViewAnimation : NSViewAnimation

// Property
@property (nonatomic, copy) HMViewAnimationCompletion completion;

// Initialize
+ (void)animateWithAnimations:(NSArray*)animations
duration:(NSTimeInterval)duration copmletion:(void (^)(void))copmletion;

@end

実装はこうです。

@implementation HMViewAnimation

+ (void)animateWithAnimations:(NSArray*)animations 
        duration:(NSTimeInterval)duration copmletion:(void (^)(void))completion
{
    // Create view animation object
    HMViewAnimation*    viewAnimation;
    viewAnimation = [[HMViewAnimation alloc] initWithViewAnimations:animations];
    [viewAnimation setDuration:duration];
    [viewAnimation setDelegate:viewAnimation];
    viewAnimation.completion = completion;

    // Start animation
    [viewAnimation startAnimation];
}

- (void)animationDidEnd:(NSAnimation*)animation
{
    // Invoke completion
    if (_completion) {
        _completion();
    }
}

@end

簡単ですね。トリッキーなことは何もしていませんが、なかなかに便利です。

    • nanashi
    • 2014年 1月27日

    ビューのフレームを変更するだけであれば +[NSAnimationContext runAnimationGroup:completionHandler:] でいいのではないでしょうか。

  1. トラックバックはまだありません。