Multiview application

In this tutorial we cover the following topics


General information

Our goal in this tutorials seems to be very easy: we want to write an application where

  • we will have one “root” (or main) screen;
  • we will have two child screens switchable from root screen;
  • on every child screen we will have also a button to switch back the root screen.

That’s it. It is just enough to be complicated.

Of course we could achieve the same functionality by writing a one-screen application, but we’re taking this more complex approach to demonstrate the mechanics of a multiscreen – being more precisely: multiview – application. Behind the scene there are actually three screens represented by three view controllers interacting in this simple application. One that controls the first view (screen), second that controls the second view (screen), and a third special controller that swaps the other two in and out when we press a button.

Most multiview applications use the same basic pattern. The place where all the views and view controllers for the application are collected is known as storyboard. Usually a storyboard with an instance of a controller class that is responsible for managing other views is created. Because this controller manage which view is currently being shown to the user, so we call this controller the root controller. This root controller is often an instance of UINavigationController or UITabBarController, because both offers natural approach to views switching.


  1. Step 1: create a new project
    Create a new project as we did it many times before, so

    1. Select File | New | Project…
    2. Select Single View Application on the template selection sheet.
    3. As the product name enter iOS Multiview
    4. Set the Language to Objective-C, devices pop-up button to Universal and make sure the check box labeled Use Core Data is unchecked.

    001

  2. Step 2: create a root controller
    It’s not necessary but to make the role of the main view controller clear, we will rename it with a more appropriate name: RootController is perfect.

    1. Select ViewController.h in the Project Navigator.
    2. In the editor area double-click the class name after @interface and then right-click it.
    3. In the menu that appears, select Refactor | Rename….
    4. The dialog should appear – make sure that option Rename related files is checked and change the view controller name to RootController.
    5. Press Preview button and next Save.

    002

  3. Step 3: add the content view controllers
    It’s not necessary but to make the role of the main view controller clear, we will rename it with a more appropriate name: RootController is perfect.

    1. In the Project Navigator, right-click the iOS Multiview group and select New File….
    2. Choose Cocoa Touch Class from the iOS Source section in the template dialog and then press Next
    3. Name the new class FirstViewController, make it a subclass of UIViewController. Because we are going to add this controller to the storyboard later manually, so make sure that the Also create XIB file check box is not checked.
    4. Press Next and then press Create to save the files for the new view controller.
    5. Repeat above steps to create the second content view controller (named SecondViewController.

    003

    004

    005

  4. Step 4: modify root controller
    Add (or modify) the following code to the RootController.m

    #import "RootController.h"
    #import "FirstViewController.h"
    
    @interface RootController ()
    @property (strong, nonatomic) FirstViewController *firstViewController;
    @end
    
    @implementation RootController
    
    - (IBAction)switchViews:(id)sender { }
    
    ... [Some existing code] ...
    
    @end
    
  5. Step 5: add buttons to RootController and set correct constraints
    1. In the Project Navigator, select Main.storyboard.
      006
    2. Now, let’s add a two buttons to the view.
      007
    3. Change the button’s labels as First and Second
    4. In Attributes inspector, View section, set tag for the First button as 1.
    5. Set correct constraints
      010

      011

      012

      013

    6. Link the toolbar button to our action method in RootController.
      008

      009

  6. Step 6: the RootController view code
    Before any action you can read this article.
    Add (or modify) the following code to the RootController.m

    - (IBAction)switchViews:(id)sender {
        int tag = (int)[sender tag];
        // Create the new view controller, if required.
        if (tag == FIRST_BUTTON) {
            if (!self.firstViewController) {
                self.firstViewController = [self.storyboard
                                             instantiateViewControllerWithIdentifier:@"First"];
            }
        }
        
        // Switch view controllers.
        if (tag == FIRST_BUTTON) {
            self.firstViewController.view.frame = self.view.frame;
            [self switchToViewController:self.firstViewController];
        }
    }
    
    - (void)switchToViewController:(UIViewController *)toVC {
        if (toVC != nil) {
            [self addChildViewController:toVC];
            [self.view addSubview:toVC.view];
            [toVC didMoveToParentViewController:self];
        }
    }
    
  7. Step 7: add a new scene to storyboard
    1. Select Main.storyboard to open it in Interface Builder, so we can add a new scene for FirstViewController.
    2. From the object library, drag out another View Controller and drop it in the editing area next to the existing one. At this point our storyboard has two scenes, each of which can be loaded dynamically and independently while the application is running.
    3. Single-click the yellow View Controller icon in the row of icons at the top of the new scene. Next press Alt+Command+3 to bring up the Identity Inspector. In the Custom Class section as Class select FirstViewController.

      014

      015

    4. In the Identity Inspector fill the Storyboard ID field with First value. We need this identifier for our new view controller to be able to find it inside the storyboard.
    5. In the middle of First View Controler’s view add Go back button.
    6. 016

    7. Create action method connected to Go back button
      017

      018

    8. Add the following code to FirstViewController.m file
      - (IBAction)buttonPressGoBack:(UIButton *)sender {
          [self willMoveToParentViewController:nil];
          [self.view removeFromSuperview];
          [self removeFromParentViewController];
      }
      
  8. Step 8: working with segues
    We are going to work with segues, so let’s explain what this term means.

    Segue as a noun means an uninterrupted transition from one piece of music or film scene to another.
    Segue as a verb means (in music and film) a move without interruption from one song, melody, or scene to another (for example allowing one song to segue into the next).

    We can repeat above step to add scene for SecondViewController with Storyboard ID value equal to Second. Instead of this let’s show how segues can be used for switching view controllers. For more details please refer to

    Let’s start

    1. Select Main.storyboard to open it in Interface Builder, so we can add a new scene for SecondViewController.
    2. From the object library, drag out another View Controller and drop it in the editing area next to the existing ones. If you want, instead of editing arrea you can put this View Controller in Document Outline
      019

      020

    3. Single-click the yellow View Controller icon in the row of icons at the top of the new scene. Next press Alt+Command+3 to bring up the Identity Inspector. In the Custom Class section as Class select SecondViewController.
    4. Select View item under Second View Controller Scene in Document Outline and change background property in Attributes inspector to the color you like
      021
    5. Create segue. To do this between view controllers in the same storyboard file, Control-click an appropriate element in the first view controller, drag to the target view controller and select Show from popup menu.
      022

      023
      You shoud see graphical representation of the egue you have just created.
      024
      The starting point of a segue must be a view or object with a defined action, such as a control, bar button item, or gesture recognizer. You can also create segues from cell-based views such as tables and collection views.

    6. In the middle of Second View Controler’s view add Go back button.
    7. The next few substeps is used to creating an unwind segue.

      Choose the view controller that should appear onscreen at the end of an unwind segue (RootController).

    8. Define an unwind action method on the view controller you chose.
      - (IBAction)myUnwindAction:(UIStoryboardSegue*)unwindSegue
      

      You must define an unwind action method in one of your view controllers before trying to create the corresponding unwind segue in Interface Builder. The presence of that method is required and tells Interface Builder that there is a valid target for the unwind segue. Use the implementation of your unwind action method to perform any tasks that are specific to your app. You can also use the unwind action to update the current view controller before the unwind segue finishes.

    9. Navigate to the view controller that initiates the unwind action (SecondViewController).
    10. Control-click the button (or other object) that should initiate the unwind segue. This element should be in the view controller you want to dismiss.
    11. Drag to the Exit object at the top of the view controller scene.
    12. 025
      and select your unwind action method from the relationship panel.
      026
      You can verify what you did in button’s Connections inspector
      027

  9. Step 9: animating the transition
    You may notice that while transition from Root to Second (transition with segue) is nice, transition from Root to First is kind of abrupt. Let’s fix it. Add (or modify) the following code to the RootController.m

    	// Switch view controllers.
        [UIView beginAnimations:@"Switch animation from Root to First" context:NULL];
        [UIView setAnimationDuration:0.5];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        if (tag == FIRST_BUTTON) {
            [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight
                                   forView:self.view cache:YES];
            self.firstViewController.view.frame = self.view.frame;
            [self switchToViewController:self.firstViewController];
        }
        [UIView commitAnimations];
    

    where

    • [UIView beginAnimations:@"Switch animation from Root to First" context:NULL];
      To tell iOS that we want a change animated, we need to declare an animation block and specify how long the animation should take. Animation blocks are declared by using the UIView class method beginAnimations:context:. The first paramtere is an animation block title. This title comes into play only if we take more direct advantage of Core Animation, the framework behind this animation. The second parameter is a (void *) that allows us to specify an object (or any other C data type) whose pointer you would like associated with this animation block.
    • [UIView setAnimationDuration:0.5];
      Set the duration of the animation.
    • [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
      Set the animation curve, which determines the timing of the animation. The default, which is a linear curve, causes the animation to happen at a constant speed. The option we set here, as many other people do because this gives the animation a more natural, less mechanical appearance, is UIViewAnimationCurveEaseInOut. This specifies that the animation should start slow but speed up in the middle, and then slow down again at the end.
    • [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight
      forView:self.view cache:YES];

      Specify the transition we want to use. We can select one of the following

      • UIViewAnimationTransitionFlipFromLeft
      • UIViewAnimationTransitionFlipFromRight
      • UIViewAnimationTransitionCurlUp
      • UIViewAnimationTransitionCurlDown
      • UIViewAnimationTransitionNone
    • [UIView commitAnimations];
      Finish specifying the changes to be animated. Everything between the start of the animation block and the call to commitAnimations will be animated together.
  10. Step 10: animating the transition (from First to Root)
    Add (or modify) the following code to the FirstViewController.m
    I have no idea, why the code below doesn’t work. Any suggestion how to fix it are welcome.

    - (IBAction)buttonPressGoBack:(UIButton *)sender {
        [UIView beginAnimations:@"Switch animation from First to Root" context:NULL];
        [UIView setAnimationDuration:0.5];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
                               forView:self.view cache:YES];
        
        [self willMoveToParentViewController:nil];
        [self.view removeFromSuperview];
        [self removeFromParentViewController];
        
        [UIView commitAnimations];
    }