Configuring the View Controller Classes
The next step before we start
coding is to set the view controller instances we’ve added to the tab
bar controller so that they point to the AreaViewController, VolumeViewController, and SummaryViewController classes and their related views (AreaView, VolumeView, and SummaryView).
Select the first view
controller icon in the MainWindow.xib. (It should contain the Area tab
bar item.) Open the Identity Inspector (Command+4) and use the Class
drop-down to choose AreaViewController.
Without closing the inspector, switch to the Attributes view
(Command+1) and use the NIB Name drop-down to select the AreaView XIB.
Set the view controller classes and NIBs for the other two view
controller instances in the project.
Implementing the Area View
Although
we haven’t really written any code specific to switching views or
managing view controllers, the TabbedCalculation application can be
built and executed and will happily switch views using the tab bar. No
need for inserting subviews or clearing views. It just works!
We can now work with our view
controller classes just as we would in any other application. The tab
bar controller instance will take care of swapping the views when
needed. We’ll start with the area calculation view.
Adding Outlets and Actions
In the area view, the
application will calculate the area of a rectangle given the length and
width, and the area of a circle, given the radius. We’ll need UITextFields for each of these values, and two UILabel instances for the calculation results.
The view controller will need to access the instance of the SummaryViewController to increment a count of the calculations performed. It will provide calculate and hideKeyboard
methods to perform the calculation and hide the input keyboard when the
background is tapped, respectively. All told, we’ll need six IBOutlets and two IBActions. These are the naming conventions we’ve used in the sample project:
rectWidth (UITextField): Field for entering the width of a rectangle
rectLength (UITextField): Field for entering the length of a rectangle
circleRadius (UITextField): Field for entering the radius of a circle
rectResult (UILabel): The calculated area of the rectangle
circleResult (UILabel): The calculated area of the circle
summaryViewController (SummaryViewController): The instance of the Summary view
calculate (method): Performs the area calculation
hideKeyboard (method): Hides the onscreen keyboard
Got all that? Good! Within Xcode, open the AreaViewController.h header file and edit the contents to read as shown in Listing 2.
Listing 2.
1: #import <UIKit/UIKit.h> 2: #import "SummaryViewController.h" 3: 4: @interface AreaViewController : UIViewController { 5: IBOutlet UITextField *rectWidth; 6: IBOutlet UITextField *rectLength; 7: IBOutlet UITextField *circleRadius; 8: IBOutlet UILabel *rectResult; 9: IBOutlet UILabel *circleResult; 10: IBOutlet SummaryViewController *summaryViewController; 11: } 12: 13: @property (retain, nonatomic) UITextField *rectWidth; 14: @property (retain, nonatomic) UITextField *rectLength; 15: @property (retain, nonatomic) UITextField *circleRadius; 16: @property (retain, nonatomic) UILabel *rectResult; 17: @property (retain, nonatomic) UILabel *circleResult; 18: 19: -(IBAction)calculate:(id)sender; 20: -(IBAction)hideKeyboard:(id)sender; 21: 22: @end
|
We’ll need to access a method within the SummaryViewController
instance, so, in line 2, we import the header for the summary class.
Lines 5–10 declare the outlets for the fields, labels, and Summary view
controller. Lines 13–17 then declare these as properties. Finally, lines
19–20 declare two IBActions that we’ll be triggering based on Touch Up events in the interface.
Creating the View
Based solely on the code,
you should be able to get a pretty good sense for what the view is going
to look like. The finished version of our sample AreaView is shown in Figure 5.
Notice that we’ve included two images (UIImageView)
in sample application view. These serve as cues for users so that they
understand what is meant by length, width, radius, and so on (hey, you
never know!). If you want to add these to your version of the
application, drag the CircleArea.png and RectArea.png files to your
Xcode Resources folder. You can also add the SphereVolume.png and
BoxVolume.png images, which are used in the volume view.
Now it’s your turn to build the view. Open AreaView.xib, and begin by dragging three instances of UITextField
to the view. Two should be grouped together for the length and width
entry for a rectangle; the third will be for the radius. After you’ve
added the fields to the view, select each and open the Attributes
Inspector (Command+1). Set the text field traits so that the keyboard is
set to a number pad, as shown in Figure 6.
Drag instances of UILabel to the view and use them to label each of the fields.
The results of the area calculations need to be displayed near the entry fields, so add two additional UILabel
instances to the view—one located near the fields for the rectangle,
the other near the radius field. Double-click to edit and clear their
contents, or set them to 0 as the default. Use two more UILabels
to create Area labels. Visit all the labels and fields with the
Attributes Inspector (Command+1) and set a size that is appropriate for
the iPhone screen.
If you’d like to add the
images to the view, add two image views from the library, positioning
one beside the rectangle fields, the other beside the radius fields.
Open the Attributes Inspector (Command+1) for each image view and choose
the RectArea.png or CircleArea.png images.
To finish the view, we need two buttons. Add the first button to the bottom of the view and name it Calculate. The second button traps background touches and triggers the hideKeyboard
method. Add a button that spans the entire background. Use the Layout
menu to send it to the back, or drag its icon into the Interface Builder
Document window so that it falls at the top of the View hierarchy. Open
the Attributes Inspector (Command+1) for the button and choose Custom
for the button type to make the button invisible, as demonstrated in Figure 7.
When you’ve finished with the
view layout, you’ll have quite a few objects in the hierarchy. If you
expand the Document window, it should resemble what we’ve created in Figure 8.
Connecting Outlets and Actions
After
creating an appropriate user interface for the area view, connect the
objects to the instance variables that we defined earlier. Control-drag
from the File’s Owner icon to each of the three UITextField instances. When prompted, create the connection from the field to the correct variable.
Assign rectResult and circleResult by Control-dragging from the File’s Owner icon to the two UILabels that will hold the results for the area calculations.
For the two buttons, Control-drag from the button to the File’s Owner icon. Set calculate as the event for the Calculate button, and hideKeyboard for the custom background button.
Implementing the Area Calculation Logic
We have our inputs, our outputs, and a trigger for the calculate method. Let’s tie them together to finish up the area view. Switch back to Xcode and edit the AreaViewController.m file.
Although it isn’t quite
necessary for a project this size, defining constants for commonly used
values can be helpful in creating readable code. With this in mind,
define a constant, Pi, near the top of the file. We’ll use this in the calculation of the circle’s area:
Next, after the @implementation directive, synthesize the getters/setters for all of the properties defined in the header file:
@synthesize rectWidth;
@synthesize rectLength;
@synthesize rectResult;
@synthesize circleRadius;
@synthesize circleResult;
Now for the real work—implementing the calculate method. Add the method definition shown in Listing 3 to the class.
Listing 3.
1: -(IBAction)calculate:(id)sender { 2: float floatRectResult=[rectWidth.text floatValue]* 3: [rectLength.text floatValue]; 4: float floatCircleResult=[circleRadius.text floatValue]* 5: [circleRadius.text floatValue]*Pi; 6: NSString *stringRectResult=[[NSString alloc] 7: initWithFormat:@"%1.2f",floatRectResult]; 8: NSString *stringCircleResult=[[NSString alloc] 9: initWithFormat:@"%1.2f",floatCircleResult]; 10: rectResult.text=stringRectResult; 11: circleResult.text=stringCircleResult; 12: [stringRectResult release]; 13: [stringCircleResult release]; 14: 15: [summaryViewController updateTotal]; 16: }
|
We’re working with the
assumption that you’re comfortable with the equations for calculating
the area of a rectangle (l*w) and a circle (Pi*r^2), but a few pieces of
the code might be unfamiliar. Lines 2–3 and 4–5 calculate the area for
the rectangle and circle, respectively, and store the results in two new
floating point variables (floatRectResult, floatCircleResult). The calculations take advantage of the NSString class method floatValue to provide a floating-point number from the user’s input.
By the Way
The floatValue method
will return 0.0 if the user types in gibberish. This means we always
have a valid calculation to perform, even if the user enters bad
information.
Lines 6–7 and 8–9 allocate and initialize two strings to hold the formatted results. Using initWithFormat: and the format "%1.2f”
to create the strings, we ensure that there will always have at least
one digit before the decimal and two decimal places in the result.
Lines
10–13 set the results within the view and then release the temporary
strings. The last step, in line 15, uses an instance method of the SummaryViewController, updateTotal, to update the total number of calculations performed. Defining this method will be one of the last things we do this hour.
All in all, the calculation logic isn’t difficult to understand. The only pieces missing are the implementation of hideKeyboard and releasing our objects in dealloc. Go ahead and define hideKeyboard as follows:
-(IBAction)hideKeyboard:(id)sender {
[rectWidth resignFirstResponder];
[rectLength resignFirstResponder];
[circleRadius resignFirstResponder];
}
Wrap up the implementation of the area view controller by editing dealloc to release the objects we used:
- (void)dealloc {
[rectWidth release];
[rectLength release];
[circleRadius release];
[rectResult release];
[circleResult release];
[super dealloc];
}
AreaViewController and AreaView
are complete. Building the volume view and view controller will follow a
very similar process, so we’ll move quickly through the next section.