-
Notifications
You must be signed in to change notification settings - Fork 336
1.4 UIViewController2 ModalViewController (storyboard)
参考 : 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 には親子関係ができます。
具体的には親の ViewController の property:presentedViewController に表示されている ModalViewController の参照が代入され、ModalViewController の propterty:presentingViewController に親の ViewController の参照が代入される。
注意:modalViewController property は iOS6 から deplecated なので使用しないようにしましょう。
また、ModalViewController の上に ModalViewController をだすこともできる。
表示方法は storyboard から直接表示する方法と、コード上からViewControllerを生成して表示する方法があります。
1.3のサンプルプロジェクトをさらに改造します。https://github.com/mixi-inc/iOSTraining/tree/master/SampleProjects/1.3/MyFirstProject
追加で新しい View Controller のサブクラスを作ってください。クラス名は "MySecondViewController" としました。 できたら1.3と同様にstoryboardにViewControllerを追加して、クラスを"MySecondViewController"にしてください。 わかりやすくするために、MySecondViewController上に何かラベルを配置しておくと良いかもしれません。
segue(セグエ)とは二つのシーン間の遷移方法についての設定のことです。どのViewControllerからどのViewControllerを、どのように表示するか、などを設定します。 主に、storyboard上で遷移を決めるときに利用します。
storyboard上にViewControllerを追加できたら、MixiSampleViewController上のボタンをタップした時に、MySecondViewControllerを表示できるようにsegueを追加しましょう。
storyboardのMixiSampleViewControllerの上のUIButtonをcontrolボタンを押しながらドラッグします。 するとマウスポインタ上とボタンの間に青い線が出ると思います。そのままMySecondViewController上までドラッグします。(図3)
図3
MySecondViewControllerまできたらドロップしてください。すると、図4のようなパネルが出ると思うので、その中から "present modally" を選択します。
図4
ここまでできれば、segueの追加は完了です。 実はここまでできれば、MySecondViewControllerは表示することができます。シミュレータから実行して、MixiSampleViewControllerのボタンをタップするとMySecondViewControllerが表示されると思います。
今のサンプルではボタンをタップした時に自動的にsegueが実行され、MySecondViewController が表示されました。 実際にアプリを作る際はデータのロード完了時まで遷移したくない、などのケースもあるため任意のタイミングで実行する必要があります。 そのようなケースではプログラム上からsegueを実行します。
MixiSampleViewControllerにもう一つボタンを追加し、ボタンタップ時に呼ばれるメソッドを一つ追加してください。
今回は secondButtonTapped:
というメソッドにしています。
次にstoryboard上でsegueを選択し、Xcodeの右側にあるユーティリティのAttribute Inspectorから Stroryboard Segue Identifierを入力します。 このIdentifierはstoryboard上で実行されるsegueの識別子でプログラムから呼び出す時などに使います。名前については他とIdentifierと重複しない限り自由につけることができます。 今回は "presentMySecondViewController" としました。
それではボタンタップ時に呼ばれるメソッドにこの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に何かデータを渡して遷移することがよくあります。
そのようなケースでは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を表示することもできます。iOS4以前はstoryboardがなくそれに伴ってsegueを利用することもできませんでした。 その際の資料については 1.4-UIViewController2---ModalViewController を見ていただくとよいと思います。
storyboardを使いつつ、ただsegueを利用しない、という方法について簡単に紹介します。
先ほど実装したメソッド -secondButtonTapped:
を修正して利用します。
まずはstoryboard内にあるUIViewControllerにIdentifierをつけます。 ユーティリティのIdentity InspectorからStoryboard ID をつけます。このIDをつけることで、コード上から このViewControllerを一つだけ生成することが可能になります。ここにつけるIDは他のものと被らなければ問題ありません。 ここではクラス名と同じで"MySecondViewController"としました。
では実際に生成して表示します。#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です。
- modalTransitionStyle 画面遷移の方法
typedef enum {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal,
UIModalTransitionStyleCrossDissolve,
UIModalTransitionStylePartialCurl,
} UIModalTransitionStyle;
- modalPresentationStyle - iPad の場合に表示形式を変更できる
typedef enum {
UIModalPresentationFullScreen = 0,
UIModalPresentationPageSheet,
UIModalPresentationFormSheet,
UIModalPresentationCurrentContext,
} UIModalPresentationStyle;
[self dismissViewControllerAnimated:YES completion:nil];
このメソッドを呼べば、トップレベルの ModalViewController が dismiss されます。公式ドキュメントには原則として呼び出した ViewControlelr が消すべきと書いてあります。状況に応じて使い分けてください。
MixiChildViewController で閉じるボタンを押したことを MixiViewControlelr が知る必要があります。このようにある VC から VC へ何らかの通知を送る手段の一つとして 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];
}
}
プロトコルはメッソド宣言の集合体です。上記では、MixiChildViewController が MixiChildViewControllerDelegate というプロトコルで、他のクラスに任せたいメソッドを宣言しています。
実際に処理を任せたいクラスのインスタンスが代入されています。id で、MixiChildViewControllerDelegate を採用しているオブジェクトの代入することを条件づけることが出来ます。この場合 MixiViewController が入ります。MixiViewController は自身で MixiChildViewController の参照を持つので、こちらで weak property にしておかないと循環参照が起きます。
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];
}
複数ある場合は "," でつなげます。
MixiViewController.h
#import "MixiChildViewController.h"
@interface MixiViewController : UIViewController <MixiChildViewControllerDelegate, AaaDelegate, BbbDelegate>
これを忘れると MixiChildViewController から通知を受け取ることが出来ませんのでお忘れなく。
protocol の採用をすることで method の補完が効くようになります。
Modal の 表示、非表示アニメーションが同時に起きるとアニメーションの衝突でクラッシュするので気をつけてください。
はじめに
-
導入
-
1.3 UIViewController1 UIViewController のカスタマイズ(xib, autoresizing)
-
UIKit 1 - container, rotate-
-
UIKit 2- UIView -
-
UIKit 3 - table view -
-
UIKit 4 - image and text -
-
ネットワーク処理
-
ローカルキャッシュと通知
-
Blocks, GCD
-
設計とデザインパターン
-
開発ツール
-
テスト
-
In-App Purchase
-
付録