In this tutorial we cover the following topics
- General information
- Step 1: create a new project
- Step 2: create a root controller
- Step 3: add the content view controllers
- Step 4: modify root controller
- Step 5: add buttons to RootController and set correct constraints
- Step 6: The RootController view code
- Step 7: add a new scene to storyboard
- Step 8: working with segues
- Step 9: animating the transition
- Step 10: animating the transition (from First to Root)
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.
- Step 1: create a new project
Create a new project as we did it many times before, so- Select File | New | Project...
- Select Single View Application on the template selection sheet.
- As the product name enter
iOS Multiview
- Set the Language to Objective-C, devices pop-up button to Universal and make sure the check box labeled Use Core Data is unchecked.
- 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.- Select
ViewController.h
in the Project Navigator. - In the editor area double-click the class name after
@interface
and then right-click it. - In the menu that appears, select Refactor | Rename....
- The dialog should appear - make sure that option Rename related files is checked and change the view controller name to
RootController
. - Press Preview button and next Save.
- Select
- 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.- In the Project Navigator, right-click the iOS Multiview group and select New File....
- Choose Cocoa Touch Class from the iOS Source section in the template dialog and then press Next
- Name the new class
FirstViewController
, make it a subclass ofUIViewController
. 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. - Press Next and then press Create to save the files for the new view controller.
- Repeat above steps to create the second content view controller (named
SecondViewController
.
- Step 4: modify root controller
Add (or modify) the following code to theRootController.m
1234567891011121314#import "RootController.h"#import "FirstViewController.h"@interface RootController ()@property (strong, nonatomic) FirstViewController *firstViewController;@end@implementation RootController- (IBAction)switchViews:(id)sender { }... [Some existing code] ...@end - Step 5: add buttons to RootController and set correct constraints
- In the Project Navigator, select
Main.storyboard
.
- Now, let’s add a two buttons to the view.
- Change the button's labels as First and Second
- In Attributes inspector, View section, set tag for the First button as 1.
- Set correct constraints
- Link the toolbar button to our action method in RootController.
- In the Project Navigator, select
- Step 6: the RootController view code
Before any action you can read this article.
Add (or modify) the following code to theRootController.m
123456789101112131415161718192021222324- (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.storyboardinstantiateViewControllerWithIdentifier:@"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];}} - Step 7: add a new scene to storyboard
- Select
Main.storyboard
to open it in Interface Builder, so we can add a new scene for FirstViewController. - 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.
- 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.
- 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. - In the middle of First View Controler's view add Go back button.
- Create action method connected to Go back button
- Add the following code to
FirstViewController.m
file12345- (IBAction)buttonPressGoBack:(UIButton *)sender {[self willMoveToParentViewController:nil];[self.view removeFromSuperview];[self removeFromParentViewController];}
- Select
- 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 toSecond
. Instead of this let's show how segues can be used for switching view controllers. For more details please refer toLet's start
- Select
Main.storyboard
to open it in Interface Builder, so we can add a new scene for SecondViewController. - 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
- 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.
- Select View item under Second View Controller Scene in Document Outline and change background property in Attributes inspector to the color you like
- 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.
You shoud see graphical representation of the egue you have just created.
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. - In the middle of Second View Controler's view add Go back button.
- 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).
- Define an unwind action method on the view controller you chose.
1- (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.
- Navigate to the view controller that initiates the unwind action (SecondViewController).
- 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.
- Drag to the Exit object at the top of the view controller scene.
and select your unwind action method from the relationship panel.
You can verify what you did in button's Connections inspector
- Select
- 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 theRootController.m
1234567891011// 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:UIViewAnimationTransitionFlipFromRightforView: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 methodbeginAnimations: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 tocommitAnimations
will be animated together.
- Step 10: animating the transition (from First to Root)
Add (or modify) the following code to theFirstViewController.m
I have no idea, why the code below doesn't work. Any suggestion how to fix it are welcome.
12345678910111213- (IBAction)buttonPressGoBack:(UIButton *)sender {[UIView beginAnimations:@"Switch animation from First to Root" context:NULL];[UIView setAnimationDuration:0.5];[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeftforView:self.view cache:YES];[self willMoveToParentViewController:nil];[self.view removeFromSuperview];[self removeFromParentViewController];[UIView commitAnimations];}