UINavigationControllerにカスタムのフェードトランジションを実装する

| コメント(0) | トラックバック(0)
こんにちは。開発担当のICTFです。

UINavigationControllerは画面をpushあるいはpopする際、自動的にスライドする様なトランジションが適用されます。
今回はそのトランジションをカスタマイズする方法についてご紹介します。
実装は様々なトランジションに対応できるような方法をとりますが、サンプルとしてフェードトランジションを実装します。

カスタムトランジションを実装するにあたり、次の点を重要視して設計します。
  • pushする際に設定したトランジションをpopする際に「自動で」適用する。
  • 一度(白など)一色にフェードアウトした後、次の画面がフェードインする。
UINavigationControllerに対してCATransitionを普通に適用した場合、表示中の画面と次の画面が一瞬混ざってしまいます。
場合によっては有効かもしれませんが、今回は汎用性の高い「一度何かしらの色に塗りつぶされた後に次の画面が表示される」という処理を目指します。
この塗りつぶし処理を実現するため、遷移元と遷移先の画面の間に一時的なUIViewControllerを挟みます。

それでは実装に入ります。
まず一時的な一色のUIViewControllerを実装します。
フェード以外のトランジションにもすぐ対応できるよう、基本的な処理はベースクラスに実装します。
準備としてCATransitionを使うため、

#import <QuartzCore/QuartzCore.h>

を追加して下さい。

【AnimViewBase.h】

// AnimNavigationControllerで用いるトランジション付き画面のベースクラス

@interface AnimViewBase : UIViewController

{

UIViewController* _nextViewController;

float _duration;

BOOL _navigationBarHidden;

}


-(id) initWithBaseViewController:(UIViewController*)baseViewController nextViewController:(UIViewController*)nextViewController color:(UIColor*)color duration:(float)duration backButtonTitle:(NSString*)backButtonTitle;


// トランジションアニメーションのデザイン

-(CATransition*) createTransition;


@end


【AnimViewBase.m】

@interface AnimViewBase ()


// トランジション開始タイマーイベント

-(void) onScheduleTransition;


@end


@implementation AnimViewBase


-(id) initWithBaseViewController:(UIViewController*)baseViewController nextViewController:(UIViewController*)nextViewController color:(UIColor*)color duration:(float)duration backButtonTitle:(NSString*)backButtonTitle;

{

if (self = [super init]) {

_nextViewController = [nextViewController retain];

_duration = duration;

self.view.backgroundColor = color;

self.title = baseViewController.title;

// ナビゲーションバーのデザイン

if (backButtonTitle) {

UIBarButtonItem* backButton = [[[UIBarButtonItem alloc] init] autorelease];

backButton.title = backButtonTitle;

self.navigationItem.backBarButtonItem = backButton;

}

// トランジションアニメーションのデザイン

[baseViewController.navigationController.view.layer addAnimation:[self createTransition] forKey:nil];

}

return self;

}


-(void) viewWillAppear:(BOOL)animated

{

[super viewWillAppear:animated];

_navigationBarHidden = self.navigationController.navigationBarHidden;

self.navigationController.navigationBarHidden = YES;

}


-(void) viewWillDisappear:(BOOL)animated

{

[super viewWillDisappear:animated];

self.navigationController.navigationBarHidden = _navigationBarHidden;

}


-(void) viewDidAppear:(BOOL)animated

{

[super viewDidAppear:animated];

// トランジション開始スケジュール

[NSTimer scheduledTimerWithTimeInterval:_duration * 0.5 target:self selector:@selector(onScheduleTransition) userInfo:nil repeats:NO];

}


// トランジション開始タイマーイベント

-(void) onScheduleTransition

{

[self.navigationController.view.layer addAnimation:[self createTransition] forKey:nil];

if (_nextViewController) {

// 進む遷移

[self.navigationController pushViewController:_nextViewController animated:NO];

[_nextViewController release];

_nextViewController = nil;

}

else {

// 戻る遷移

[self.navigationController popViewControllerAnimated:NO];

}

}


// トランジションアニメーションのデザイン

-(CATransition*) createTransition

{

return nil;

}


@end


createTransitionが空実装ですが、これは派生先のクラスで実装します。
次にフェードトランジションを行なう派生クラスを実装します。

【FadeInOutViewController.h】

#import "AnimViewBase.h"


@interface FadeInOutViewController : AnimViewBase

{

}


@end


【FadeInOutViewController.m】

- (void)viewDidLoad

{

    [super viewDidLoad];

}


- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


// トランジションアニメーションのデザイン

-(CATransition*) createTransition

{

CATransition* transition = [CATransition animation];

transition.duration = _duration * 0.5;

transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];

transition.type = kCATransitionFade;

return transition;

}


@end


基本機能はベースクラスで実装済みなので、createTransitionの実装のみです。

最後に重要な機能である「push時のトランジション設定を、pop時にも自動的に適用する」
機能を実装します。
UINavigationControllerを継承し、popViewControllerAnimated:をオーバーライドします。

【UINavigationControllerEx.h】

@interface UINavigationControllerEx : UINavigationController


@end


【UINavigationControllerEx.m】

#import "AnimViewBase.h"


@interface UINavigationControllerEx ()


@end


@implementation UINavigationControllerEx


- (UIViewController *)popViewControllerAnimated:(BOOL)animated

{

if (self.viewControllers.count > 1) {

UIViewController* prevView = [self.viewControllers objectAtIndex:self.viewControllers.count - 2];

if ([prevView isKindOfClass:[AnimViewBase class]]) {

// トランジション画面クラスの場合、トランジション設定を取得する

[self.view.layer addAnimation:[((AnimViewBase*)prevView) createTransition] forKey:nil];

animated = NO;

}

}

return [super popViewControllerAnimated:animated];

}


@end


pop直前に一つ前の画面を調べ、AnimViewBaseを継承するクラスであった場合にトランジションを適用します。

使用方法は以下の通りです。

1. UINavigationControllerの生成処理をUINavigationControllerExに変更する

UINavigationControllerEx* navigationController = [[[UINavigationControllerEx alloc] initWithRootViewController:view] autorelease];


2. トランジションを加えたい画面遷移に、FadeInOutViewControllerを使用する。

NextView* NextView = [[[NextView alloc] init] autorelease];

FadeInOutViewController* fadeView = [[[FadeInOutViewController alloc] initWithBaseViewController:self nextViewController:NextView color:[UIColor whiteColor] duration:0.8 backButtonTitle:@"戻る"] autorelease];

[self.navigationController pushViewController:fadeView animated:NO];


注意事項として、pushViewControllerのanimatedはNOにして下さい。


トラックバック(0)

トラックバックURL: http://www.ict-fractal.com/MovableType/mt/mt-tb.cgi/54

コメントする

Twitterボタン
Twitterブログパーツ