今回はUINavigationControllerを使った画面遷移のチュートリアルです。

サンプル: https://github.com/stack3/UINavigationControllerSamples

サンプルを起動して、Push & Popを選択すると以下のような画面になります。

01

Pushボタンを押すと次の画面へ移動します。

02

Popボタンを押すと前の画面へ戻ります。左上のSample1ボタンを押した時も同様に前の画面へ戻ります。

03-1

再度、Pushを押して次の画面へ遷移し、Pop to Topボタンを押すと、最初の画面へ戻ります。

UINavigationController

UINavigationControllerは、1つ以上のViewControllerを内包して画面遷移の管理をするViewControllerです。UINavigationControllerのUINavigationBarを除いた部分に、内包するViewControllerを表示します。

ちなみにUINavigationControllerは画面下にUIToolbarを表示することもできます。なので正確にはUINavigationBarとUIToolbarを除く部分に内包するViewControllerを表示すると言ったほうが良いです。

initWithRootViewControllerメソッド

UINavigationControllerは単独で表示しても意味がないので、内包する最初の画面となるViewControllerをinitWithRootViewControlerで指定する必要があります。

UIViewController *con = [[STViewController alloc] init];
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:con];

pushViewControllerメソッド

UINavigationController#pushViewControllerメソッドで次の画面となるViewControllerを指定します。引数animatedをYESにすると画面が右から左へスライドして、次の画面が現れます。

STSample1ViewController *con = [[STSample1ViewController alloc] init];
[self.navigationController pushViewController:con animated:YES];

ViewControllerはnavigationControllerプロパティを通じて、自分を内包しているUINavigationControllerを参照することができます。画面の遷移するきっかけを作るのは、UINavigationControllerではなく内包されているViewController側ですので、このようにselfからnavigationControllerプロパティを参照することが多いでしょう。

popViewControllerメソッド

前の画面に戻るためにはUINavigationController#popViewControllerメソッドを呼び出します。

[self.navigationController popViewControllerAnimated:YES];

ただしNavigationBar左上の戻るボタンを押した時は、プログラムを書かなくても前の画面に戻ります。

popToRootViewControllerメソッド

pushViewControllerで次へ次へといくつもの画面遷移をした後に、一気に一番最初の画面に戻りたい時は、popToRootViewControllerを呼びます。

[self.navigationController popToRootViewControllerAnimated:YES];

STViewControllerクラス

最初のメニュー画面のViewControllerです。UITableViewを使ってメニュー項目を表示しています。細かい実装はここでは割愛します。

STAppDelegateでアプリケーションが起動した時、STViewControllerを内包するUINavigationControllerが最初の画面になるようにします。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // STViewControllerの生成
    UIViewController *con = [[STViewController alloc] init];
    // UINavigationControllerを生成
    // RootViewControllerをSTViewControllerとする
    UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:con];

    // UINavigationControllerを最初の画面とする    
    self.viewController = navCon;
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

メニューの行が選択されたときに、STSample1ViewControllerが次の画面として表示されるように、pushViewControllerしています。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == _STMenuItemPushAndPop) {
        STSample1ViewController *con = [[STSample1ViewController alloc] init];
        [self.navigationController pushViewController:con animated:YES];
〜〜以下略〜〜

STSample1ViewController

Pushボタンを押した時、STSample2ViewControllerを次の画面として表示、Popボタンを押した時は前の画面に戻るようにしています。

- (void)didTapPushButton
{
    STSample2ViewController *con = [[STSample2ViewController alloc] init];
    [self.navigationController pushViewController:con animated:YES];
}

- (void)didTapPopButton
{
    [self.navigationController popViewControllerAnimated:YES];
}

STSample2ViewController

Popボタンを押した時は前の画面に戻り、Pop to Topボタンを押した時は、最初の画面に戻るようにしています。

- (void)didTapPopButton
{
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)didTapPopToTopButton
{
    [self.navigationController popToRootViewControllerAnimated:YES];
}

内包するViewControllerのライフサイクル

UINavigationControllerが内包するViewControllerのライフサイクルに関するメソッドは以下のように呼ばれます。

  • Sample1ViewControllerをpushViewControllerする
  • Sample1ViewController#viewDidLoad
  • Sample1ViewController#viewWillAppear
  • Sample1ViewController#viewDidAppear
  • Sample2ViewControllerをpushViewControllerする
  • Sample1ViewController#viewWillDisappear
  • Sample2ViewControllerのviewWillAppear
  • Sample1ViewControllerのviewDidDisappear
  • Sample2ViewControllerのviewDidAppear

またこの後、メモリが足らなくなるとSample1ViewController#viewDidUnloadが呼ばれviewが一旦破棄される可能性がある

  • Sample2ViewController#viewWillDisappear
  • Sample1ViewControllerのviewWillAppear
  • Sample2ViewControllerのviewDidDisappear
  • Sample1ViewControllerのviewDidAppear

もし、Sample1ViewControllerのviewが破棄されていたら、viewDidAppearの前にviewDidLoadが呼ばれることに注意

その2へ続く