Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

1.4 UIViewController2 ModalViewController (storyboard)

yuichi takeda edited this page Jan 19, 2015 · 8 revisions

参考 : UIViewController Class Reference | View Controller Programming Guide for iOS

概要

UIViewControllerには他のViewControllerと連携して新しいViewControllerを表示するなどの役割もあります。 連携のやり方には代表的なものに Modal, Navigation Controller, TabBarController などの方法があり、この章ではModalを用いた方法を解説します。

Modal View Controllerは「現在のViewControllerで行っている操作を一時中断して新しいViewControllerを表示する」というケースで利用されます。公式ドキュメントには以下のようなケースで使うことを想定しています。

  • ユーザから直ちに情報を収集するため
  • 何らかのコンテンツを一時的に表示するため
  • 作業モードを一時的に変更するため
  • デバイスの向きに応じて代替のインターフェイスを実装するため
  • 特殊なアニメーショントランジションを使用する(またはトランジションなしの)新しいビュー 階層を表示するため

UIViewController は一つの ModalView を表示することが可能で、そのときに、Modal を表示する ViewController と ModalViewController には親子関係ができます。

modal1

View Controller Programming Guide for iOS から引用

具体的には親の ViewController の property:presentedViewController に表示されている ModalViewController の参照が代入され、ModalViewController の propterty:presentingViewController に親の ViewController の参照が代入される。

注意:modalViewController property は iOS6 から deplecated なので使用しないようにしましょう。

modal_deprecated

また、ModalViewController の上に ModalViewController をだすこともできる。

modal2 View Controller Programming Guide for iOS から引用

表示方法

表示方法は storyboard から直接表示する方法と、コード上からViewControllerを生成して表示する方法があります。

storybaordから直接表示する方法

1.3のサンプルプロジェクトをさらに改造します。https://github.com/mixi-inc/iOSTraining/tree/master/SampleProjects/1.3/MyFirstProject

追加で新しい View Controller のサブクラスを作ってください。クラス名は "MySecondViewController" としました。 できたら1.3と同様にstoryboardにViewControllerを追加して、クラスを"MySecondViewController"にしてください。 わかりやすくするために、MySecondViewController上に何かラベルを配置しておくと良いかもしれません。

segueを追加して表示する

segue(セグエ)とは二つのシーン間の遷移方法についての設定のことです。どのViewControllerからどのViewControllerを、どのように表示するか、などを設定します。 主に、storyboard上で遷移を決めるときに利用します。

storyboard上にViewControllerを追加できたら、MixiSampleViewController上のボタンをタップした時に、MySecondViewControllerを表示できるようにsegueを追加しましょう。

storyboardのMixiSampleViewControllerの上のUIButtonをcontrolボタンを押しながらドラッグします。 するとマウスポインタ上とボタンの間に青い線が出ると思います。そのままMySecondViewController上までドラッグします。(図3)

図3 図3

MySecondViewControllerまできたらドロップしてください。すると、図4のようなパネルが出ると思うので、その中から "present modally" を選択します。

図4 図4

ここまでできれば、segueの追加は完了です。 実はここまでできれば、MySecondViewControllerは表示することができます。シミュレータから実行して、MixiSampleViewControllerのボタンをタップするとMySecondViewControllerが表示されると思います。

プログラム上からsegueを実行する

今のサンプルではボタンをタップした時に自動的にsegueが実行され、MySecondViewController が表示されました。 実際にアプリを作る際はデータのロード完了時まで遷移したくない、などのケースもあるため任意のタイミングで実行する必要があります。 そのようなケースではプログラム上からsegueを実行します。

MixiSampleViewControllerにもう一つボタンを追加し、ボタンタップ時に呼ばれるメソッドを一つ追加してください。 今回は secondButtonTapped: というメソッドにしています。

ボタンとハンドラ追加

次にstoryboard上でsegueを選択し、Xcodeの右側にあるユーティリティのAttribute Inspectorから Stroryboard Segue Identifierを入力します。 このIdentifierはstoryboard上で実行されるsegueの識別子でプログラムから呼び出す時などに使います。名前については他とIdentifierと重複しない限り自由につけることができます。 今回は "presentMySecondViewController" としました。

img

それではボタンタップ時に呼ばれるメソッドにこのsegueを呼び出します。呼び出すには UIViewControllerのインスタンスメソッドである -performSegueWithIdentifier:sender: を利用します。 先ほど定義したメソッドの中で -performSegueWithIdentifier:sender: を呼び出します。一つ目の引数はSegueのIdentifierで、先ほどstoryboard上で設定したものを利用します。二つ目のsegueはこのsegueを呼び出したクラスです。よくselfを代入します。

- (IBAction)secondButtonTapped:(id)sender {
    [self performSegueWithIdentifier:@"presentMySecondViewController" sender:self];
}

新たに追加したボタンをタップしたときにMySecondViewControllerが出ればOKです。

segueで表示するViewControllerにデータを与える

segueを用いて画面遷移を行うとき、表示したいViewControllerに何かデータを渡して遷移することがよくあります。 そのようなケースではUIViewControllerのインスタンスメソッド-prepareForSegue:senderを利用します。 UIViewControllerのサブクラスを作った際に自動的にコードスニペットが.mファイルにコメントアウトで記述されています。 このコメントアウトを外して実際に実装します。

この-prepareForSegue:senderはsegueが呼ばれて実際に実行されるまでの間、その遷移に関して追加で行う処理がある場合に実装するメソッドとなります。 引数は実行されるsegueとsenderです。

画面遷移は一つの画面に対して複数あることがあります。そのためどの画面遷移かを見分けて処理を行う必要があります。 その際は segue.identifier を用いて切り分けます。

また、遷移先のViewControllerが必要な場合は segue.destinationViewController で必要なViewControllerを取得することができます。

以下のようなサンプルになります。

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.

    if ([segue.identifier isEqualToString:@"presentMySecondViewController"]) {
        UIViewController *destination = segue.destinationViewController;
    }

}

segueを使わずにViewControllerを表示する

segueを一切使わず、ViewControllerを表示することもできます。iOS4以前はstoryboardがなくそれに伴ってsegueを利用することもできませんでした。 その際の資料については 1.4-UIViewController2---ModalViewController を見ていただくとよいと思います。

storyboardを使いつつ、ただsegueを利用しない、という方法について簡単に紹介します。 先ほど実装したメソッド -secondButtonTapped: を修正して利用します。

まずはstoryboard内にあるUIViewControllerにIdentifierをつけます。 ユーティリティのIdentity InspectorからStoryboard ID をつけます。このIDをつけることで、コード上から このViewControllerを一つだけ生成することが可能になります。ここにつけるIDは他のものと被らなければ問題ありません。 ここではクラス名と同じで"MySecondViewController"としました。

img

では実際に生成して表示します。#import "MySecondViewController.h" を忘れないでください。

生成するには UIStroyboardのインスタンスメソッド -instantiateViewControllerWithIdentifier:を用います。 このメソッドの引数に先ほど定義したstoryboardIDを渡します。UIViewControllerがstoryboardから生成された場合、プロパティにstoryboardがあるのでそれを利用します。

ViewControllerからViewControllerを表示するにはメソッド presentViewController:animated:completion: を用います。 このメソッドの一つ目の引数に表示したいViewControllerを渡します 。

- (IBAction)secondButtonTapped:(id)sender {
    MySecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"MySecondViewController"];
    [self presentViewController:secondViewController animated:YES completion:nil];
}

このような実装になります。同じく表示されればOKです。

ModalViewControllerを閉じる

delegate

Unwind Segue

表示オプション

  • modalTransitionStyle 画面遷移の方法
typedef enum {
   UIModalTransitionStyleCoverVertical = 0,
   UIModalTransitionStyleFlipHorizontal,
   UIModalTransitionStyleCrossDissolve,
   UIModalTransitionStylePartialCurl,
} UIModalTransitionStyle;
  • modalPresentationStyle - iPad の場合に表示形式を変更できる
typedef enum {
   UIModalPresentationFullScreen = 0,
   UIModalPresentationPageSheet,
   UIModalPresentationFormSheet,
   UIModalPresentationCurrentContext,
} UIModalPresentationStyle;

消し方と delegate

dismissViewController

[self dismissViewControllerAnimated:YES completion:nil];

このメソッドを呼べば、トップレベルの ModalViewController が dismiss されます。公式ドキュメントには原則として呼び出した ViewControlelr が消すべきと書いてあります。状況に応じて使い分けてください。

dismissViewController

delegate と protocol

MixiChildViewController で閉じるボタンを押したことを MixiViewControlelr が知る必要があります。このようにある VC から VC へ何らかの通知を送る手段の一つとして delegate があります。

delegate

delegate とはあるクラスで処理できない処理を他のクラスに代わりに処理させるパターンです。この場合、MixiChildViewController でボタンが押されたイベントだけキャッチし、MixiChildViewControlelr を閉じる処理は MixiViewControlelr に任せることにします。

MixiChildViewController.h

#import <UIKit/UIKit.h>

@protocol MixiChildViewControllerDelegate <NSObject> // [1] プロトコルの宣言
-(void)didPressCloseButton;
@end

@interface MixiChildViewController : UIViewController

@property (nonatomic, weak) id<MixiChildViewControllerDelegate> delegate; // [2] delegate オブジェクト

- (IBAction)pressClosedButton:(id)sender;

@end

MixiChildViewController.m

-(IBAction)pressClosedButton:(id)sender
{
    // [3] delegate オブジェクトにメッセージを送信
    if([_delegate respondsToSelector:@selector(didPressCloseButton)]){
        [_delegate didPressCloseButton];
    }
}

[1] protocol

プロトコルはメッソド宣言の集合体です。上記では、MixiChildViewController が MixiChildViewControllerDelegate というプロトコルで、他のクラスに任せたいメソッドを宣言しています。

[2] delegate オブジェクト

実際に処理を任せたいクラスのインスタンスが代入されています。id で、MixiChildViewControllerDelegate を採用しているオブジェクトの代入することを条件づけることが出来ます。この場合 MixiViewController が入ります。MixiViewController は自身で MixiChildViewController の参照を持つので、こちらで weak property にしておかないと循環参照が起きます。

[3] delegate オブジェクトにメッセージを送信

respondsToSelector: で delegate 先に delegate method が実装されているかを確認します。実装されていれば、実際にメッセージを送ります。

MixiViewController.h

#import "MixiChildViewController.h"

@interface MixiViewController : UIViewController <MixiChildViewControllerDelegate> // [4] protocol の採用

MixiViewController.m

- (void)pressModalButton:(id)sender
{
    MixiChildViewController *mixiChildViewController = [[MixiChildViewController alloc] init];
    mixiChildViewController.delegate = self; // [5] delegate 先として自身を代入
    [self presentViewController:mixiChildViewController animated:YES completion:nil];
}

// [6] delegate method の実装
#pragma mark - MixiPostViewControllerDelegate methods
-(void)didPressCloseButton
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

[4] protocol の採用

複数ある場合は "," でつなげます。

MixiViewController.h

#import "MixiChildViewController.h"

@interface MixiViewController : UIViewController <MixiChildViewControllerDelegate, AaaDelegate, BbbDelegate>

[5] delegate 先として自身を代入

これを忘れると MixiChildViewController から通知を受け取ることが出来ませんのでお忘れなく。

[6] delegate method の実装

protocol の採用をすることで method の補完が効くようになります。

注意事項

Modal の 表示、非表示アニメーションが同時に起きるとアニメーションの衝突でクラッシュするので気をつけてください。

はじめに

  1. iOSについて

  2. Xcode最初のステッフ

  3. 導入

  4. Objective C の基礎

  5. メモリ管理

  6. 1.3 UIViewController1 UIViewController のカスタマイズ(xib, autoresizing)

  7. 1.3 UIViewController1 UIViewController のカスタマイズ(storyboard)

  8. UIViewController2 - ModalViewController

  9. UIViewController2 - ModalViewController(storyboard)

  10. UIViewController3 - ライフサイクル

  11. HomeWork 1 Objective C の基本文法

  12. HomeWork 2 UIViewControllerとModalViewController

  13. HomeWork 3 UIViewController + Animation

  14. UIKit 1 - container, rotate-

  15. UINavigationController

  16. UITabController

  17. Custom Container View Controller

  18. Supporting Multiple Interface Orientations

  19. HomeWork 1 - タブバーからモーダルビューを表示する

  20. HomeWork 2 - NavigationController

  21. HomeWork 2.3 デバイスことに回転対応

  22. UIKit 2- UIView -

  23. UIView

  24. UIView のカスタマイズ

  25. UIView Animation

  26. HomeWork 1 - UIScrollView

  27. UIKit 3 - table view -

  28. UITableView について

  29. UITableViewとNavigationController

  30. custom UITableViewCell の作成

  31. UITableViewのその他のオプション、カスタマイズ

  32. HomeWork 1 - Dynamic height with a custom uitableviewcell

  33. UIKit 4 - image and text -

  34. UIImagePickerController

  35. Assets Library

  36. UITextFiled, UITextView

  37. KeyboardNotification

  38. Homework 1 - フォトの複数枚選択

  39. ネットワーク処理

  40. NSURLConnection

  41. JSONのシリアライズとデシリアライズ

  42. UIWebView

  43. ローカルキャッシュと通知

  44. NSUserDefaults, Settings Bundle

  45. NSFileManager

  46. Key Value Observing

  47. NSNotification、NSNotificationCenter を用いた通知

  48. UILocalNotification

  49. Blocks, GCD

  50. Blocks

  51. GCD

  52. 【演習】GCD,-Blocksを用いたHTTPリクエストマネージャの作成

  53. 設計とデザインパターン

  54. クラス設計 1

  55. クラス設計 2

  56. [クラス設計演習] (https://github.com/mixi-inc/iOSTraining/wiki/9.3-%E3%82%AF%E3%83%A9%E3%82%B9%E8%A8%AD%E8%A8%88%E6%BC%94%E7%BF%92)

  57. 開発ツール

  58. Instruments, デバッガ

  59. CocoaPods

  60. テスト

  61. iOS開発におけるテスト

  62. GHUnit

  63. Kiwi

  64. KIF

  65. In-App Purchase

  66. In-App Purchase

  67. 付録

  68. Tips of Xcode

  69. Auto Layout 入門

  70. Auto Layout ドリル

Edit sidebar

Clone this wiki locally