Adding Toolbar Controls
The
MultipleViews application that we’re building now requires a single
toolbar with buttons for each of the three views that we want to
display. The toolbar itself will be added as a subview of the view in
the MultipleViewsViewController.xib file.
If you haven’t already, open
the MultipleViewsViewController.xib file in Interface Builder. The view
contained in this XIB file, as you know from previous view-based
applications, is what will be added to the application’s window when it
first launches. Instead of providing all of the onscreen content,
however, we just want this view and its view controller to manage the
toolbar and the user’s interactions with it.
Open the view and, using the Library objects (Tools, Library), drag an instance of a toolbar (UIToolbar) to the bottom of the view. You should now have an empty view with a single-button toolbar visible.
Adding and Editing Toolbar Buttons
We will need three buttons for this project. Drag a bar button item (UIBarButton)
from the Library to the toolbar. An insertion point will appear where
the button will be added. Repeat this process until there are a total of
three buttons (one for each view) in the toolbar.
Double-click the button’s title
to switch to an editable mode. Edit each button title to correspond to
one of the views that needs to be displayed: First View, Second View,
Third View.
Did you Know?
If you have difficulty selecting
the buttons directly in the layout view, you may also select them using
the Document window and edit their titles by accessing the Attributes
Inspector (Command+1).
After editing the titles, you
may want to resize the buttons to create a uniform appearance in the
toolbar. You can use the Size Inspector (Command+3) to adjust the width
numerically, or just click and drag the resize handle that appears to
the right of the currently selected button.
The end result should resemble Figure 8.
By the Way
Bar
button items do not have to be text-labeled buttons. Alternatively, you
can set an image file to be used as the button representation in the
Attributes Inspector. We will be using this feature of the tab bar UI
element in the next project.
Adding Outlets and Actions
Now that all the interface elements are in place for the MultiViews application, we need to connect them to code. The MultiViewsViewController
object will handle the switching of the views, so we need to edit the
class to include outlets for each of the view controllers, as well as
actions for each of the toolbar buttons, and a new method clearView that we’ll use to clear the contents of the view as we switch between them.
Edit MultipleViewsViewController.h to reflect the code in Listing 1.
Listing 1.
1: #import <UIKit/UIKit.h> 2: 3: @class FirstViewController; 4: @class SecondViewController; 5: @class ThirdViewController; 6: 7: @interface MultipleViewsViewController : UIViewController { 8: IBOutlet FirstViewController *firstViewController; 9: IBOutlet SecondViewController *secondViewController; 10: IBOutlet ThirdViewController *thirdViewController; 11: } 12: 13: @property (retain, nonatomic) FirstViewController *firstViewController; 14: @property (retain, nonatomic) SecondViewController *secondViewController; 15: @property (retain, nonatomic) ThirdViewController *thirdViewController; 16: 17: -(IBAction) loadSecondView:(id)sender; 18: -(IBAction) loadThirdView:(id)sender; 19: -(IBAction) loadFirstView:(id)sender; 20: 21: -(void) clearView; 22: 23: @end
|
Let’s quickly run through
what we’ve done here. Because this class needs to be aware of our other
view controller classes, we first declare the view controller classes in
lines 3–5.
Lines 8–10 create IBOutlets for each of our view controller instances (firstViewController, secondViewController, and thirdViewController); we’ll need to access them to switch between views.
In lines 13–15, we declare these three instances as properties.
Lines 17–19 declare three methods for switching views and expose them as IBActions for Interface Builder (loadFirstView, loadSecondView, and loadFirstView).
Finally, on line 21, a new method, clearView, is declared. It will be used to remove the old content from our view when we switch to a new view.
Connecting Outlets and Actions
Save the changes you’ve made to
MultiViewsViewController.h, and jump back into the
MultiViewsViewController.xib file in Interface Builder. We can now make
our final connections before writing the view switching code.
From the Document window, Control-drag from the File’s Owner icon to the instance of FirstViewController. When prompted for an outlet, choose firstViewController, as shown in Figure 9.
Repeat this process for the secondViewController and thirdViewController instances, choosing the appropriate outlet when prompted.
Next, expand the view and
toolbar hierarchy to show the three bar button items that we added
earlier. Control-drag from the First View button to the File’s Owner
icon. When prompted, choose the loadFirstView sent action.
Do the same for the two other buttons, connecting the Second View button to loadSecondView and the third to loadThirdView. The interface connections are now complete, and we can finish up the implementation of the view loading methods.
Implementing the View Switch Methods
To implement the view switching, we’ll be making use of a UIView instance method called insertSubview:atIndex:.
This method inserts a view as a subview of another view—just like
creating a hierarchy of views within Interface Builder. By inserting a
subview at an index of 0 into the view containing our toolbar, we will
effectively “float” the toolbar view on top of the subview.
Begin
the implementation by opening MultipleViewsViewController.m in Xcode.
Import the headers from the three view controller classes so that we can
properly access them in the code:
#import "MultipleViewsViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
#import "ThirdViewController.h"
Next, after the @implementation directive, use @synthesize to create the getters and setters for the view controller instances (firstViewController, secondViewController, thirdViewController):
@synthesize firstViewController;
@synthesize secondViewController;
@synthesize thirdViewController;
Create the method to load the first view, loadFirstView, as follows:
-(IBAction) loadFirstView:(id)sender {
[self.view insertSubview:firstViewController.view atIndex:0];
}
This single line of code uses the insertSubview:atIndex: method of the MultiViewsViewController’s view instance (which contains our toolbar!) to add a subview that will appear below it. That’s all there is to it!
Following this pattern, implement the loadSecondView and loadThirdView methods to insert their respective view controller’s views as subviews to the toolbar view.
By the Way
If you’re confused why self.view is the view containing the toolbar, look at the structure of the project and the XIB files. We’re adding the loadView methods to the MultiViewsViewController class, so self refers to the instance of that class. The MultiViewsViewController has a single view with a toolbar that we added earlier, so self.view, within this context, is just a reference to that view.
After you’ve finished the view loading implementation, don’t forget to release the view controllers in the dealloc method:
- (void)dealloc {
[firstViewController release];
[secondViewController release];
[thirdViewController release];
[super dealloc];
}
Setting a View When the Application Starts
If
you try to run the application now, it should work, but it probably
won’t do quite what you may expect. When the application first starts,
it loads the initial view containing the toolbar but nothing else. Until
a toolbar button is pressed, none of our three content views are
visible. A much more user-friendly approach is to automatically load
content as soon as the application starts.
To automatically switch to one of the views, we can simply use one of the loadView methods that we just defined.
Editing MultipleViewsViewController.m, implement the viewDidLoad method as follows:
- (void)viewDidLoad {
[self loadFirstView:nil];
[super viewDidLoad];
}
By calling the loadFirstView:
method upon successful loading of the view containing the toolbar, we
ensure that some initial content is available for users without them
first having to press any buttons.
By the Way
Because loadFirstView
is defined as requiring a parameter in its implementation, we must pass
a parameter when using it here. Because the parameter (sender) is not
used in the function, we can safely pass nil with no ill effects.
Clearing the Current View
Try building and
executing the application again. This time, an initial view should load,
but the application still won’t perform correctly. You’ll likely see
sporadic behavior as you try to navigate between views or the views will
overlay on top of one another, creating an onscreen mess. The problem
is that while we’re adding subviews as the toolbar button is pressed,
we’re never removing them again! What we need to do to stabilize the
application’s behavior is to identify and remove the current subview
each time the toolbar button is pressed.
When a view is added to another as a subview (its superview), a property called superview is set appropriately. In other words, when firstViewController.view is added as a subview to our toolbar view, its superview property is set to the toolbar view. If a view hasn’t been added as a subview, the property is nil. So, how can this help us? Easy: By testing to see whether the superview
property is set, we can identify which view has been made active and
then remove it when it’s time to switch views. To remove a view from its
superview, we can use the removeFromSuperview instance method.
Add the clearView method shown in Listing 2 to MultipleViewsViewController.m.
Listing 2.
-(void) clearView { if (firstViewController.view.superview) { [firstViewController.view removeFromSuperview]; } else if (secondViewController.view.superview) { [secondViewController.view removeFromSuperview]; } else { [thirdViewController.view removeFromSuperview]; } }
|
In this implementation, we test for the existence of the superview property in all of the view controller’s views and, if we find it, we use removeFromSuperview to remove the view.
All that remains is to add clearView so that it is called before any view is loaded. A completed version of the loadFirstView method is shown in Listing 12.3.
Listing 3.
-(IBAction) loadFirstView:(id)sender { [self clearView]; [self.view insertSubview:firstViewController.view atIndex:0]; }
|
Make the same change to loadSecondView and loadThirdView,
and then retest your application. It should now cleanly switch between
the different views by touching the toolbar buttons, as shown in Figure 10.