Finishing the Interface
The only functional piece that is missing from our interface is a button (UIButton) that we can use to manually trigger the getFlower
method anytime we want. Without the button, we’d have to switch between
colors using the segmented control if we wanted to see a new flower
image. This button does nothing more than trigger an action (getFlower), something you’ve done repeatedly in the past few hours, so this should be a walk in the park for you by now.
Drag a button into the view, positioning it in the center of the screen above the web views. Edit the button title to read Get New Photo.
Finally, select the button and
open the Connections Inspector (Command+2). Drag from the Touch Up
Inside event to the File’s Owner icon in the Document window. When
prompted choose the getFlower action, as shown in Figure 13.
Did you Know?
Although your interface
may be functionally complete, you may want to select the view itself
and set a background color. Keep your interfaces clean and friendly!
The interface, shown in Figure 14, is complete! Switch back to Xcode and let’s get coding!
Implementing the View Controller Logic
There are two pieces of functionality that our view controller needs to implement via two action methods. The first, toggleFlowerDetail, will show and hide the flowerDetailView web view depending on whether the switch has been flipped on (show) or off (hide). The second method, getFlower, will load a flower image into the flowerView web view and details on that photograph into the flowerDetailView web view. We’ll start with the easier of the two, toggleFlowerDetail.
Hiding and Showing the Detail Web View
A useful property of any object that inherits from UIView
is that you can easily hide (or show) it within your iPhone application
interfaces. Because almost everything you see onscreen inherits from
this class, this means you can hide and show labels, buttons, fields,
images, and yes, other views. To hide an object, all we need to do is
set its Boolean property hidden to TRUE or YES (both have the same meaning). So, to hide the flowerDetailView, we write the following:
flowerDetailView.hidden=YES;
To show it again, we just reverse the process, setting the hidden property to FALSE or NO:
flowerDetailView.hidden=NO;
To implement the logic for the toggleFlowerDetail:
method, we need to figure out what value the switch is currently set
to. As mentioned earlier in the lesson, we can check the state of a
toggle switch through the isOn method that returns a Boolean value of TRUE/YES if the switch is set to on or FALSE/NO if it is off.
Because we don’t have an outlet specifically set aside for the switch, we’ll use the sender variable to access it in our method. When the toggleFlowerDetail
action method is called, this variable is set to reference the object
that invoked the action (in other words, the switch). So, to check to
see whether the switch is on, we can write the following:
If ([sender isOn]) { <switch is on> } else { <switch is off> }
Now, here’s where we can get clever (you’re feeling clever, right?). We want to hide and show the flowerDetailView using a Boolean value and we get a Boolean value from the switch’s isOn method. This maps to two conditions:
When [sender isOn] is YES, the view should not be hidden (flowerDetailView.hidden=NO)
When [sender isOn] is NO, the view should be hidden (flowerDetailView.hidden=YES)
In other words, the state of the switch is the exact opposite of what we need to assign to the hidden
property of the view. In C (and therefore Objective-C), to get the
opposite of a Boolean value, we just put an exclamation mark in front
(!). So all we need to do to hide or show flowerDetailView is to set the hidden property to ![sender isOn]. That’s it! A single line of code!
Implement toggleFlowerDetail: in FlowerWeb right after the @synthesize directives. The full method should look a lot like this:
-(IBAction)toggleFlowerDetail:(id)sender{
flowerDetailView.hidden=![sender isOn];
}
Loading and Displaying the Flower Image and Details
To fetch our flower images,
we’ll be making use of a feature provided by the Flora Photographs
website for specifically this purpose. We’ll be following four steps to
interact with the website:
1. | We’ll get the chosen color from the segmented control.
|
2. | We will generate a random number called a session ID so that floraphotographs.com can track our request.
|
3. | We will request the URL http://www.floraphotographs.com/showrandomiphone.php?color=<color>&session=<session ID>, where <color> is the chosen color and <session ID> is the random number. This URL will return a flower photo.
|
4. | We will request the URL http://www.floraphotographs.com/detailiphone.php?session=<session ID>, where <session ID> is the same random number. This URL will return the details for the previously requested flower photo.
|
Let’s go ahead and see what this looks like in code, and then discuss details behind the implementation. Add the getFlower code block, shown in Listing 2, following the toggleFlowerDetail method that you implemented.
Listing 2.
1: -(IBAction)getFlower:(id)sender { 2: NSURL *imageURL; 3: NSURL *detailURL; 4: NSString *imageURLString; 5: NSString *detailURLString; 6: NSString *color; 7: int sessionID; 8: 9: color=[colorChoice titleForSegmentAtIndex: 10: colorChoice.selectedSegmentIndex]; 11: sessionID=random()%10000; 12: 13: imageURLString=[[NSString alloc] initWithFormat: 14: @"http://www.floraphotographs.com/showrandomiphone.php?color=%@&session=%d" 15: ,color,sessionID]; 16: detailURLString=[[NSString alloc] initWithFormat: 17: @"http://www.floraphotographs.com/detailiphone.php?session=%d" 18: ,sessionID]; 19: 20: imageURL=[[NSURL alloc] initWithString:imageURLString]; 21: detailURL=[[NSURL alloc] initWithString:detailURLString]; 22: 23: [flowerView loadRequest:[NSURLRequest requestWithURL:imageURL]]; 24: [flowerDetailView loadRequest:[NSURLRequest requestWithURL:detailURL]]; 25: 26: flowerDetailView.backgroundColor=[UIColor clearColor]; 27: 28: [imageURLString release]; 29: [detailURLString release]; 30: [imageURL release]; 31: [detailURL release]; 32: }
|
This is the most
complicated code that you’ve written so far, but it’s broken down into
the individual pieces, so it’s not difficult to understand:
Lines 2–7 declare the variables that we need to prepare our requests to the website. The first variables, imageURL and detailURL, are instances of NSURL that will contain the URLs that will be loaded into the flowerView and flowerDetailView web views. To create the NSURL objects, we need two strings, imageURLStringdetailURLString, and which we’ll format with the special URLs that we presented earlier, including the color and sessionID values.
In lines 9–10, we retrieve the title of the selected segment in our instance of the segmented control: colorChoice. To do this, we use the object’s instance method titleForSegmentAtIndex along with the object’s selectedSegmentIndex property. The result, [colorChoice titleForSegmentAtIndex: colorChoice.selected SegmentIndex], is stored in the string color and is ready to be used in the web request.
Line 11 generates a random number between 0 and 9999 and stores it in the integer sessionID.
Lines 13–18 prepare imageURLString and detailURLString with the URLs that we will be requesting. The strings are allocated, and then the initWithFormat
method is used to store the website address along with the color and
session ID. The color and session ID are substituted into the string
using the formatting placeholders %@%d for strings and integers, respectively. and
Lines 20–21 allocate and create the imageURL and detailURL NSURL objects using the initWithString class method and the two strings imageURLString and detailURLString.
Lines 23–24 use the loadRequest method of the flowerView and flowerDetailView web views to load the NSURLs imageURL and detailURL, respectively. When these lines are executed, the display updates the contents of the two views.
By the Way
Although we mentioned this earlier, remember that UIWebView’s loadRequest method doesn’t handle NSURL objects directly; it expects an NSURLRequest object instead. To work around this, we create and return NSURLRequest objects using the NSURLRequest class method requestWithURL and the imageURL and detailURL objects as parameters.
Line 26 is an extra nicety that we’ve thrown in. This sets the background of the flowerDetailView web view to a special color called clearColor.
This, combined with the alpha channel value that you set earlier, will
give the appearance of a nice translucent overlay of the details over
the main image. You can comment out or remove this line to see the
difference it creates.
Did you Know?
To create web views that blend with the rest of your interface, you’ll want to keep clearColor
in mind. By setting this color, you can make the background of your web
pages translucent, meaning that the content displayed on the page will
overlay any other content that you’ve added to your iPhone view.
Finally, Lines 28–31 release all the objects that we’ve allocated in the method. Because getFlower will potentially be called over and over, it’s important that we release any memory that we might be using!
Fixing Up the Interface When the App Loads
Now that the getFlower
method is implemented, you can run the application and everything
should work—except that when the application starts, the two web views
will be empty and the detail view will be visible, even though the
toggle switch is set to off.
To fix this, we can start loading an image as soon as the app is up and running and set flowerDetailView.hidden to YES. Uncomment the viewDidLoad method and implement it as follows:
- (void)viewDidLoad {
flowerDetailView.hidden=YES;
[self getFlower:nil];
[super viewDidLoad];
}
As expected, flowerDetailView.hidden=YES will hide the detail view. Using [self getFlower:nil], we can call the getFlower: method from within our instance of the view control (referenced as self) and start the process of loading a flower in the web view. The method getFlower: expects a parameter, so we pass it nil. (This value is never used in getFlower:, however, so there is no problem with providing nil.)
Releasing the Objects
As always, we need to finish things up by releasing the objects that we’ve kept around. Edit the dealloc method to release the segmented control and two web views now:
- (void)dealloc {
[colorChoice release];
[flowerDetailView release];
[flowerView release];
[super dealloc];
}
Building the Application
Test out the final version of the FlowerWeb application by clicking Build and Run in Xcode.
Notice that you can zoom in
and out of the web view, and use your fingers to scroll around. These
are all features that you get without any implementation cost when using
the UIWebView class.
Congratulations! Another app under your belt!