A View Controller presented Modally


A navigation controller presents a series of view controllers in a certain order (Grand Central Terminal, 125th Street, Yankee Stadium), but does not require you to come back to the place from which you started. A view controller followed by a modally presented view controller are a series of view controllers presented in a certain order, with the intention that you will come back to the place from which you started.

Usually the series will consist of only two view controllers: the initial one, and one that you will visit modally (temporarily). To see a well-known example, go to the Contacts app and press + to add a contact. Press Done or Cancel to go back to the place you started from. See Modal View in the iOS Human Interface Guidelines.

Source code in Modal.zip

  1. main.m
  2. Class ModalAppDelegate
  3. Class MainViewController
  4. Class MainView
  5. Class ModalViewController
  6. Class ModalView

Bottom-to-top animation

Modal view controllers are not a subclass of UIViewController. In fact, modal view controllers are not a class at all. A modal view controller is just a plain old view controller (e.g., a UITabBarController or UINavigationController) that is displayed modally, i.e., temporarily. When the modal view controller disappears, the previous view controller reappears and you’re back where you were. A modal controller is always animated upwards when it appears and covers the previous controller, and downwards when it disappears. There’s one in the Calendar app that comes with the iPhone.

A modal controller can have another modal controller on top of it. In fact, there can be a stack of them. Every UIViewController has a modalViewController property that points to the modal view controller that is temporarily on top of it. (The property is nil if there is no modal view controller currently on top of it.) Conversely, every modal view controller has a presentingViewController property that points to the view controller waiting patiently under it. (The property is nil if there is no other controller.)

What to use it for

A navigation controller leading the user through the following series of questions. Each quesion is presented by its own view controller and view.

  1. What is your name?
  2. What is your age?
  3. Are you taking any medications? (If the answer is yes, a modally presented view controller and view will pop up and say “describe them”. The modally presented view controller and view will then disappear.)
  4. What is your email address?
  5. What is your phone number?

Things to try

  1. In the initWithNibName:bundle: method of class ModalViewController, insert a modalTransitionStyle in the custom initialization. The non-default possibilities are UIModalTransitionStyleFlipHorizontal and UIModalTransitionStyleCrossDissolve. See Transition Styles.
    	self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;	//default

  2. A modally displayed view is expected to have a navigation bar containing buttons for “Done” and (optionally) “Cancel”. The ModalView is controlled by a ModalViewController. To get a navigation bar, the ModalViewController will have to be controlled by a UINavigationController. The UINavigationController will appear modally atop the MainViewController. Make the following three changes.

    1. Give the ModalViewController a Done button that will appear if the ModalViewController is ever controlled by a UINavigationController. Uncomment the method initWithNibName:bundle: in ModalViewController.m and put the following statement into the custom initialization.
      		self.navigationItem.rightBarButtonItem =
      			[[UIBarButtonItem alloc] initWithTitle: @"Done"
      			style: UIBarButtonItemStyleDone
      			target: self
      			action: @selector(dismissModalViewController)];
    2. In the presentModalViewController of class MainViewController, change
      	ModalViewController *modalViewController =
      		[[ModalViewController alloc] initWithNibName: nil bundle: nil];
      	[self presentModalViewController: modalViewController animated: YES];
      	ModalViewController *modalViewController =
      		[[ModalViewController alloc] initWithNibName: nil bundle: nil];
      	UINavigationController *navigationController =
      		[[UINavigationController alloc] initWithRootViewController: modalViewController];
      	[self presentModalViewController: navigationController animated: YES];
      or to
      	[self presentModalViewController:
      		[[UINavigationController alloc] initWithRootViewController:
      			[[ModalViewController alloc] initWithNibName: nil bundle: nil]
      		animated: YES
    3. Now that the ModalView is displayed with a Done button, you can remove the touchesBegan:withEvent: method of class ModalView.

  3. In the initWithFrame:controller: methods of classes MainView and ModalView, change
    	self.text = @"MainView";
    	self.text = @"ModalView";
    	self.text = NSStringFromClass([self class]);
    We called the function NSStringFromClass in main.m.