スライドトランジションを SimpleViewerへ組み込む。現在の実装では NSViewのサブクラスである SimpleViewerImageView がキャプチャ画像の描画を行っている。
トランジションでは2つのビューの切り替えになる為、画像を描画するビューのインスタンスが2個必要になる。またこの2つを管理しなければならない。そこで新たに描画を担当するビュー SimpleViewerImageSubView を用意し、今までのビュー SimpleViewerImageView にはこの2つのインスタンスの管理だけを行わせることにする。
トランジション処理は SimpleViewerImageView に責務を負わせ、コントローラ向けのプログラムインターフェイスは変えない。これによってコントローラ側のコードの修正はいらなくなる。
さて動かしてみよう。


おおいい感じだ。トランジションにかかる時間は 0.25秒。いろいろ試したがこれぐらいが良さそうだ。
2009年1月15日木曜日
SimpleViewer - スライドトランジションを組み込む
投稿者
xcatsan
時刻:
6:02
ラベル: cocoa, Core Annimation, SimpleViewer, アニメーション
2009年1月14日水曜日
スライドトランジション
SimpleViewerのキャプチャ画像切り替えでスライドトランジションを使いたい。今見ている画像を別の画像が脇からスライドして出てきて追い出すやつ。CoreAnimationを使うと簡単にできるのでまずはサンプルを作って検証してみる。
サンプル:SlideTransition-1.zip
以前、検証した波紋アニメーションのコードが参考になった。今回はフィルタを使用しないのでもっと簡単にできる。
AppController.m
#import "AppContorller.h"
#import
@implementation AppContorller
-(void)awakeFromNib
{
NSRect frame = [_view frame];
_image_view1 = [[NSImageView alloc] initWithFrame:frame];
[_image_view1 setImage:[NSImage imageNamed:@"image1"]];
_image_view2 = [[NSImageView alloc] initWithFrame:frame];
[_image_view2 setImage:[NSImage imageNamed:@"image2"]];
CATransition *transition = [CATransition animation];
[transition setType:kCATransitionPush];
[transition setSubtype:kCATransitionFromTop];
[transition setDuration:0.25];
[_view setAnimations:
[NSDictionary dictionaryWithObject:transition forKey:@"subviews"]];
[[_view animator] addSubview:_image_view1];
[_view setWantsLayer:YES];
}
-(IBAction)start:(id)sender
{
[[_view animator] replaceSubview:_image_view1 with:_image_view2];
}
@end
起動時に2つのビュー(NSImageView)を用意しそれぞれ画像を貼付けておき、一方でスライド用のトランジション(CATransition)を作っておく。ボタンが押されたらこの2つのビューを NSView#replaceSubview:with: で置き換える。この置き換え行為によってトランジションのアニメーションが実行される。
注意点は2つ。
1つめはXCodeのプロジェクトに Quartz.framework を加えておくこと。これが無いとビルド時にエラーとなる。

もう一つはビューへ setWantsLayer:YES を投げること。これを忘れるとアニメーションが起らない(これで少しハマった)。
[_view setWantsLayer:YES];
実行してみるとこんな感じ。
初期状態。ここで STARTボタンを押す。

上に新しい画像が現れ、今まで見ていた画像は下へ追い出される。

下へ追い出される画像はフェードアウト効果がかかる。

終了時。完全に置き換わっている。

CATransitionの親クラス CAAnimation には Delegateが設定できて、トランジションの開始と終了イベントを捉えることもできる。
animationDidStart:
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
- - - -
検証ができたので SimpleView へ組み込んでみる。2つのビューを用意するのがポイントだな。
投稿者
xcatsan
時刻:
6:46
ラベル: cocoa, Core Annimation, アニメーション
2008年12月29日月曜日
Windowアニメーション(その3)NSViewAnimation
前回検証した NSViewAnimation クラスを使って SimpleView にフェードイン/フェードアウト効果を導入する。
パネルウィンドウのクラス SimpleViewerPanel へ show/hideメソッドを用意してこれで制御することにしよう。
SimpleViewerPanel.h
@interface SimpleViewerPanel : NSPanel {
}
- (void)show;
- (void)hide;
@end以下、実装コード。
SimpleViewerPanel.m
#define FADE_DURATION 0.25
- (void)show
{
if (![self isVisible]) {
[self setAlphaValue:0.0];
[self orderFront:self];
}
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject:self forKey:NSViewAnimationTargetKey];
[dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
[dict setObject:[NSValue valueWithRect:[self frame]] forKey:NSViewAnimationStartFrameKey];
[dict setObject:[NSValue valueWithRect:[self frame]] forKey:NSViewAnimationEndFrameKey];
NSViewAnimation *anim = [[NSViewAnimation alloc]
initWithViewAnimations:[NSArray arrayWithObject:dict]];
[anim setDuration:FADE_DURATION];
[anim setAnimationCurve:NSAnimationEaseIn];
[anim startAnimation];
[anim release];
}
- (void)hide
{
if (![self isVisible] || [self alphaValue]==0) {
return;
}
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject:self forKey:NSViewAnimationTargetKey];
[dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
NSViewAnimation *anim = [[NSViewAnimation alloc]
initWithViewAnimations:[NSArray arrayWithObject:dict]];
[anim setDuration:FADE_DURATION];
[anim setAnimationCurve:NSAnimationEaseIn];
[anim startAnimation];
[anim release];
}
組み込んでみて次のことがわかった。
(1)フェードアウトは不透明度(alpha値)が 0になり、見えなくなるだけ。
NSWindow#isVisible: YES
NSWindow#alphaValue: 1.0=>0.0
(2)フェードインは不透明度を0.0から1.0に変えるだけ。
NSWindow#isVisible: YES
NSWindow#alphaValue: 0.0=>1.0
つまりいずれも不透明度を変えるだけで、ウィンドウそのものを表示したり(#orderFront:)、非表示にしたり(#orderOut:)しているわけではない。アニメーションを行うだけのクラスなので当然の動作といえばそうなのだが、気がつくまでちょと混乱してしまった。
さて上記メソッドを呼ぶ様にした。こんな感じ。

やっぱり、フェードイン/フェードアウトがあると柔らかい感じがしていい。
なお、左上の×でウィンドウを閉じた時にもフェードアウトがかかるよう、NSWindow#close: メソッドをオーバーライドしてある。
- (void)close
{
[self hide];
}
- - - -
こんな便利なクラス(NSViewAnimation)があるとは知らなかった。もっと早く気がつけば吹き出しウィンドウのフェードアウトは簡単にできたのに。。
投稿者
xcatsan
時刻:
9:37
ラベル: NSViewAnimation, SimpleViewer, アニメーション
2008年12月28日日曜日
Windowアニメーション(その2)
引き続き調査。いろいろと情報があったが、ウィンドウのフェードアウトは NSViewAnimationを使えばよさそうなことがわかった。
NSViewAnimation Class Reference
これをつかった解説があり、ずばりフェードアウトの例が載っていた。
Animating Views and Windows
早速試してみよう。
サンプル:WindowAnimation-2.zip
前回のサンプルを流用し、メイン部分だけ書き換えた。_windowはアウトレット。あらかじめ IBで作ったウィンドウを接続してある。
AppController.m
- (void)showWindow:(id)sender
{
[_window orderFront:nil];
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject:_window forKey:NSViewAnimationTargetKey];
[dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
NSViewAnimation *anim = [[NSViewAnimation alloc]
initWithViewAnimations:[NSArray arrayWithObject:dict]];
[anim setDuration:1];
[anim setAnimationCurve:NSAnimationEaseIn];
[anim startAnimation];
[anim release];
}
最初に表示されるウィンドウのボタンを押すとこのメソッドが呼ばれる。設定値を NSMutableDictionary へ入れて後は NSViewAnimationを制御するだけ。
実行してみよう。

おお。いい感じにフェードアウトしている。静止画ではわかりづらいが、下のウィンドウが徐々に薄くなって(透明度が高くなって)最後は見えなくなる。
NSViewAnimationは NSViewAnimationStartFrameKey, NSViewAnimationEndFrameKey を使えば大きさを変えた場合のZoomアニメーションも可能になる。ただ試したところ前回同様、拡大縮小は行っていないようだ(縮小時はクリッピング)。
