L Train

   

The navigation controller moves us horizontally, east and west along 14th Street. It lets us visit a series of StationControllers, each with its own white view. An InfoController moves vertically, displaying more information for each station. It is displayed modally, i.e., temporarily.

The pentagonal button in the upper left corner (for all stations except the first one, Eighth Avenue) points to where we came from. We get this button automatically. The “Go East” button in the upper right corner (for all stations except the last one) had to be created by hand. See the initWithTitle: method of class StationController.

The above navigation controller will be called the primary navigation controller. It lets us see the bars that have the “Go East” buttons. In addition, each modal view controller will have its own secondary navigation controller. Each one lets us see a bar that has the “Done” button.

Source code in LTrain.zip

  1. main.m
  2. Class LTrainAppDelegate: the names and information instance variables were turned into properties.
  3. Classes StationController and StationView
  4. Classes InfoController and InfoView

What happens when you press “More Information” and “Done”

  1. The “more info” button in a StationView calls the moreInfo method of its StationController.

  2. The moreInfo method of the StationController creates an InfoController whose navigationItem contains a “Done” button. The InfoController creates an InfoView. Then the moreInfo method of the StationController creates a secondary navigation controller that controls the InfoController. (This navigation controller will not control any other view controllers. Its only purpose is to make the InfoController’s navigationItem visible.) Finally, the moreInfo method of the StationController displays the secondary navigation controller by calling the presentModalViewController:animated: method of the StationController.

  3. The “Done” button in the navigationItem of the InfoController calls the done method of the InfoController, which sends the dismissModalViewControllerAnimated: message to the InfoController’s own self. The dismissModalViewControllerAnimated: message is then automatically forwarded to tghe StationController that was eclipsed when the “more info” button was pressed.

Things to try

  1. In portrait orientation, a StationView is 460 = 480 – 20 pixels (or pixel pairs) high when it is initialized by its by initWithFrame:controller: method. This method correctly centers the “More Information” button at a point 230 pixels below the top edge of the StationView. But the StationView later becomes 44 pixels (or pixel pairs) shorter when the navigation bar becomes visible. The button remains 230 pixels below the top and is now too low.

    Correct this by adding the following method to class StationView.

    //Called automatically when the StationView is resized.
    
    - (void) layoutSubviews {
    	//Put the origin of the StationView at the center of the StationView.
    	CGSize s = self.bounds.size;
    	self.bounds = CGRectMake(-s.width / 2, -s.height / 2, s.width, s.height);
    }