Finishing the Interface
The remaining components of the
ImageHop application are interface features that you’ve used before, so
we’ve saved them for last. We’ll finish things up by adding a button to
start and stop the animation, along with a readout of the speed of the
animated rabbit in “hops per second.”
Adding Labels
Start by dragging two labels (UILabel) to the view. The first label should be set to read hops per second:
and be located below the slider. Add the second label, which will be
used as output of the actual speed value, to the right of the first
label.
Change the output label to read 1.00 hps
(the speed that the animation will be starting out at). Using the
Attributes Inspector (Command+1), set the text of the label to align
right; this will keep the text from jumping around as the user changes
the speed.
Finally, Control-drag from the File’s Owner icon to the output label, and choose the hopsPerSecond outlet, as shown in Figure 8.
Adding the Hop Button
The last part of the ImageHop interface is the button (UIButton)
that starts and stops the animation. Drag a new button from the Objects
Library to the view, positioning it at the bottom center of the UI.
Double-click the button to edit the title, and set it to Hop!
Like the slider, the hop button needs to be connected to an outlet (toggleButton) and an action (toggleAnimation). Control-drag from File’s Owner icon in the Document window to the button and choose the toggleButton outlet when prompted.
Next, select the button and
open the Connections Inspector (Command+2). Within the inspector, click
and drag from the circle beside the Touch Up Inside event to the File’s
Owner icon in the Document window. Connect to the toggleAnimation action. Figure 9 shows the completed interface and button connections.
The application interface is
finished. In the next section, we complete the application by writing
the code for starting and stopping the animation and setting the speed.
Implementing the View Controller Logic
The ImageHopViewController still needs a bit of work before we can call ImageHop done and finally view the animation. Two actions, toggleAnimation and setSpeed,
need to be written. These methods will handle the user’s interaction
with the ImageHop application through the button and slider,
respectively.
Starting and Stopping the Animation
When the user touches the Hop! button, the toggleAnimation method is called. This method should use the isAnimating property of the image view (imageView)
to check to see whether an animation is running. If it isn’t, the
animation should start; otherwise, it should stop. To make sure the user
interface makes sense, the button itself (toggleButton) should be altered to show the title Sit Still! if the animation is running and Hop! when it isn’t.
Add the code in Listing 3 to the ImageHopViewController implementation file after the @synthesize directives.
Listing 3.
1: -(IBAction) toggleAnimation:(id)sender { 2: if (imageView.isAnimating) { 3: [imageView stopAnimating]; 4: [toggleButton setTitle:@"Hop!" forState:UIControlStateNormal]; 5: } else { 6: [imageView startAnimating]; 7: [toggleButton setTitle:@"Sit Still!" forState:UIControlStateNormal]; 8: } 9: }
|
Lines 2 and 5 provide the two
different conditions that we need to work with. Lines 3 and 4 are
executed if the animation is running, while lines 6 and 7 are executed
if it isn’t. In line 3 and line 6, the stopAnimating and startAnimating methods are called for the image view to start and stop the animation, respectively.
Lines 4 and 5 use the UIButton instance method setTitle:forState to set the button title to the string "Hop!" or "Sit Still!". These titles are set for the button state of UIControlStateNormal. As you learned earlier this hour, the “normal” state for a button is its default state, prior to any user event taking place.
Setting the Animation Speed
The slider triggers the setSpeed
action after the user adjusts the slider control. This action must
translate into several changes in the actual application: First, the
speed of the animation (animationDuration) should change. Second, the animation should be started if it isn’t already running. Third, the button (toggleButton) title should be updated to show the animation is running. And finally, the speed should be displayed in the hopsPerSecond label.
Add the code in Listing 4 to the view controller, and then let’s review how it works.
Listing 4.
1: -(IBAction) setSpeed:(id)sender { 2: NSString *hopRateString; 3: imageView.animationDuration=2-animationSpeed.value; 4: [imageView startAnimating]; 5: [toggleButton setTitle:@"Sit Still!" 6: forState:UIControlStateNormal]; 7: hopRateString=[[NSString alloc] 8: initWithFormat:@"%1.2f hps",1/(2-animationSpeed.value)]; 9: hopsPerSecond.text=hopRateString; 10: [hopRateString release]; 11: }
|
Because we’ll need to format a string to display the speed, we kick things off by declaring an NSString reference, hopRateString, in line 2. In line 3, the image view’s (imageView) animationDuration property is set to 2 minus the value of the slider (animationSpeed.value). This, if you recall, is necessary to reverse the scale so that faster is on the right and slower is on the left.
Line 4 uses the startAnimating
method to start the animation running. Note that it is safe to use this
method if the animation is already started, so we don’t really need to
check the state of the image view. Lines 5 and 6 set the button title to
the string "Sit Still!" to reflect the animated state.
Lines 7 and 8 allocate and initialize the hopRateString instance that we declared in line 2. The string is initialized with a format of "1.2f", based on the calculation of 1 / (2 – animationSpeed.value).
Let’s break that down a bit
further: Remember that the speed of the animation is measured in
seconds. The fastest speed we can set is 0.25 (a quarter of a second),
meaning that the animation plays 4 times in 1 second (or “4 hops per
second”). To calculate this in the application, we simply divide 1 by
the chosen animation duration, or 1 / (2 – animationSpeed.value). Because this doesn’t necessarily return a whole number, we use the initWithFormat method to create a string that holds a nicely formatted version of the result. The initWithFormat parameter string "1.2f hps" is shorthand for saying the number being formatted as a string is a floating-point value (f), and that there should always be one digit on the left of the decimal and two digits on the right (1.2). The hps
portion of the format is just the “hops per second” unit that we want
to append to the end of the string. For example, if the equation returns
a value of .5 (half a hop a second), the string stored in hopRateString"0.50 hps". is set to
In line 9, the output label (UILabel) in the interface is set to the hopRateString. Once finished with the string, line 10 releases it, freeing up the memory it was using.
By the Way
Don’t worry if the math here
is a bit befuddling. This is not critical to understanding Cocoa or iOS
development, it’s just an annoying manipulation we needed to perform to
get the values the way we want them. I strongly urge you to play with
the slider values and calculations as much as you’d like so that you can
get a better sense of what is happening here and what steps you might
need to take to make the best use of slider ranges in your own
applications.
Releasing the Objects
Our development efforts have resulted in four objects that should be released when we’re finished: toggleButton, imageView, hopsPerSecond, and animationSpeed. Edit the dealloc method to release these now:
- (void)dealloc {
[toggleButton release];
[imageView release];
[hopsPerSecond release];
[animationSpeed release];
[super dealloc];
}
Well done! You’ve just completed the app!
Building the Application
To try your hand at
controlling an out-of-control bunny rabbit, click Build and Run in
Xcode. After a few seconds, the finished ImageHop application will
start, as shown in Figure 10.
By the Way
In my version of the
tutorial app, I’ve set the background to a light-green color. Feel free
to explore different layouts of the interface within what you’ve built.
You may be surprised how much variation is possible without writing a
single additional line of code!
Although ImageHop isn’t an
application that you’re likely to keep on your phone (for long), it did
provide you with new tools for your iPhone application toolkit. The UIImageView class can easily add dynamic images to your programs, while UISlider offers a uniquely touchable input solution.