Storyboard - カスタムSegueとカスタムUnwind Segueの作り方

Xcode5でさらに使いやすくなったStoryboardですが、画面遷移を表現するSegueのanimation選択肢が少なく、すぐに自分のカスタムSegueを作りたくなってしまいます。

前の画面に戻る動作も、Unwind Segueにより簡単に実装できるようになりましたが、Unwind Segueの場合、そもそもanimationの選択肢自体がないので、こちらもカスタムUnwind Segueを作りたくなります。

今回はカスタムSegueとカスタムUnwind Segueの作り方をみてみたいと思います。

標準Segueを使った画面遷移

まず標準Seugeを使った画面遷移を実装してみます。新規プロジェクトでSingle View Applicationを作成したあと、Main_iPhone.storyboardを選んでみましょう。既に一つView Controllerがあるとおもいますが、そのとなりにもう一つView Controllerをドラッグ&ドロップして作成しましょう。

画面の遷移を分かりやすくするために、それぞれのView Controllerに色をつけます。ViewControllerのViewを選択して、Backgoundの色を設定します。

両方のViewControllerに色を設定したのち、遷移開始のためのUIButtonを作成します。右下のButtonをドラッグ&ドロップして、Titleを"Next"とします。

さてつぎにSegueを作成します。作成したButtonをCtrlキーを押したままクリックし、右側のViewControlerまでドラッグ&ドロップしましょう。

ドラッグ&ドロップが完了すると、Segueの選択肢が表示されます。デフォルトでは以下の3つが表示されます。

  • push
  • modal
  • custom

pushはUINavigationControllerの場合に使用します。customはカスタムSegueを選択する場合に使用します。ここではmodalを選びましょう。

これで、標準Segueが使えるようになりました。実際に実行して試してみましょう。modalの場合

  • Cover Vertical
  • Flip Horizontal
  • Cross Dissolve
  • Partial Curl

の4種類のTransitionが選べます。

いろいろ実行して試してみましょう。

標準Unwind Segueを使った画面遷移

さて、次の画面に遷移できるようになりましたので、戻るボタンで元の画面に戻れるようにしましょう。ここまでは一行もコードを書かずに来ましたが、Unwind Segueの場合は戻り先の画面に少しだけコードを書く必要があります。

まずは戻るボタンを作成します。先ほどと同じようにButtonをドラッグ&ドロップします。戻るボタンなので、Titleを"Prev"とします。

ここで戻り先のViewControllerにコードを追加します。具体的には戻り値がIBActionで引数がUIStoryboardSegue *のメソッドを追加します。今回は戻り先がESViewControllerなので、

- (IBAction)unwindToTop:(UIStoryboardSegue *)segue
{
}

をESViewControllerクラスに追加します。メソッドを追加したら、またStoryboardの編集画面に戻り、コントロールキーを押しながら、Buttonをクリックし、そのままドラッグ&ドラッグしながら、下にある緑色のExitアイコンへ連結します。

ドラッグ&ドロップが完了すると、先ほど追加したメソッド名が選択肢として表示されるので、クリックして選択します。

これで標準Unwind Segueの設定は完了です。実行すると、Prevボタンで前の画面に戻ることが確認できると思います。 Storyboardのフレームワークのおかげで最小限のコーディングで簡単に画面遷移の実現ができることがよく分かります。

カスタムSegueの作り方

ここからが本題です。これまでは出来合いのSegueを使いましたが、自分独自のカスタムSegueを作ってみましょう。 カスタムSeugeを作るには、UIStoryBoardSegueを継承したクラスを用意します。ここでは、NextFlipSegueというクラスを用意してみましょう。

カスタムSegueではperformというメソッドを実装します。このperformの中で実際の画面遷移を実現します。ここではUIViewAnimationOptionTransitionFlipFromTopを用いた画面遷移の実装をしています。

@implementation NextFlipSegue

- (void) perform {
    UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
    UIViewController *destinationViewController = (UIViewController *)self.destinationViewController;

    [UIView transitionWithView:sourceViewController.view
                      duration:0.5
                       options:UIViewAnimationOptionTransitionFlipFromTop
                    animations:^{
                        [sourceViewController.view addSubview:destinationViewController.view];
                    }
                    completion:^(BOOL finished){
                        [sourceViewController presentViewController:destinationViewController animated:NO completion:nil];
                    }];
}

@end

完了したら、StoryboardでSegueを選び、StyleをCustomに、Segue ClassをNextFlipSegueに設定します。これで、Nextボタンを押した時のアニメーションが上下のFlipになります。とても手軽にカスタムSegueがつくれることがよく分かります。

カスタムUnwind Segueの作り方

ではUnwind SegueのほうもカスタムSegueにしてみましょう。こちらは、PrevFlipSegueという名前で実装したいと思います。同じくUIStoryboardSegueを継承したクラスとして新たなファイルを作成し、このようにperformメソッドを実装します。

@implementation PrevFlipSegue

- (void) perform {
    UIViewController *sourceViewController = (UIViewController *)self.sourceViewController;
    UIViewController *destinationViewController = (UIViewController *)self.destinationViewController;

    [UIView transitionWithView:sourceViewController.view
                      duration:0.5
                       options:UIViewAnimationOptionTransitionFlipFromTop
                    animations:^{
                        [sourceViewController.view addSubview:destinationViewController.view];
                    }
                    completion:^(BOOL finished){
                        [sourceViewController dismissViewControllerAnimated:NO completion:nil];
                    }];
}

@end

Unwind Segueの場合、通常のSegueのようにStoryboardのUIでSegueのカスタムclassを選択することができません。そこでカスタムUnwind Segueの指定はコードでする必要があります。

Unwind Segueが実行される時、戻り先のViewControllerのメソッドでsegueForUnwindingToViewControllerを探します。もしsegueForUnwindingToViewControllerが実装されている場合は、そのメソッドが返すSegueをUnwind Segueとして使用します。では、PrevFlipSegueをUnwind Segueとして指定してみましょう。

- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier
{
    return [[PrevFlipSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController];
}

をESViewControllerクラスに追加します。identifierは呼び出し元のUnwind Segueのidentifierになります。同じ画面に複数の画面から戻ってくる場合でも、このSegue identifierで動作を変えることができます。

UINavigationControllerでViewControllerを管理している場合はすこし注意が必要で、戻り先のViewControllerではなく、戻り先のViewControllerを管理しているUINavigationControllerにsegueForUnwindingToViewControllerを実装する必要があります。

カスタムSegueとカスタムUnwind Segueについて見てきました。上記コードはgithub:ESCostomSegueに置きましたので興味のある方は試してみてください。