Creating Styled Buttons
Working with buttons is
relatively straightforward, but what you may have noticed is that, by
default, the buttons you create in Interface Builder are, well, kind of
boring.
We need a single button in this project, so drag an instance of the Rounded Rect button (UIButton) from the Objects Library to the bottom of the view. Title the button Generate Story. The final view, with a default button, can be seen in Figure 11.

Although you’re certainly
welcome to use the standard buttons, you may want to explore what visual
changes you can make in Interface Builder and ultimately through code
changes.
Editing Button Attributes
To
edit a button’s appearance, your first stop is, once again, the
Attributes Inspector (Command+1). Using the Attributes Inspector, you
can dramatically change the appearance of the button. Use the Type
drop-down menu, shown in Figure 12, to choose common button types:
Rounded Rect: The default iPhone button style.
Detail Disclosure: An arrow button used to indicate additional information is available.
Info Light:
An “i” icon, typically used to display additional information about an
application or item. The “Light” version is intended for dark
backgrounds.
Info Dark: The dark (light background) version of the Info Light button.
Add Contact: A + button, frequently used to indicate the addition of a contact to the address book.
Custom: A button that has no default appearance. Usually used with button images.

In addition to choosing a button type, you can make the button interact with user touches, a concept known as changing state.
For instance, by “default,” a button is displayed unhighlighted within
the view. When a user touches a button, it changes to a highlighted “on”
state, showing that it has been touched.
Using
the Attributes Inspector, you can use the State Configuration menu to
change the button’s title, background color, or even add a graphic
image.
Setting Custom Button Images
To create custom
iPhone buttons, you’ll need to make custom images, including versions
for the highlighted on state and the default off state. These can be any
shape or size, but PNG format is recommended because of its compression
and transparency features.
After you’ve added these
to the project through Xcode, you’ll be able to select the image from
the Image or Background drop-down menus in Interface Builder’s button
attributes. Using the Image menu sets an image that appears inside the
button alongside the button title. This option enables you to decorate a
button with an icon.
Using the Background menu
sets an image that will be stretched to fill the entire background of
the button. The option lets you create a custom image as the entire
button, but you’ll need to size your button exactly to match the image.
If you don’t, the image will be stretched and pixilated in your
interface.
Another way to use custom
button images that will correctly size to your text is through the
code. We’ll apply this technique to our project now.
Remember how we created an
outlet for a button earlier in the project? We need the outlet so that
we can manipulate the button in Xcode. Control-drag from the File’s
Owner icon in the Document window in Interface Builder to the Generate
Story button. Pick the generateStory outlet when prompted, as demonstrated in Figure 13.

Now,
switch your attention to Xcode. Inside the FieldButtonFun directory is
an Images folder with two Apple-created button templates:
whiteButton.png and blueButton.png. Drag these image files into the
Resources folder in Xcode, choosing to copy the resources, if necessary,
as shown in Figure 14.
Within Xcode, open the FieldButtonFunViewController.m file and search for the method viewDidLoad, uncomment it by removing the /* */ comment markers that surround it.
Implement the viewDidLoad method using the code in Listing 2.
Listing 2.
1: -(void)viewDidLoad { 2: UIImage *normalImage = [[UIImage imageNamed:@"whiteButton.png"] 3: stretchableImageWithLeftCapWidth:12.0 4: topCapHeight:0.0]; 5: [generateStory setBackgroundImage:normalImage forState:UIControlStateNormal]; 6: UIImage *pressedImage = [[UIImage imageNamed:@"blueButton.png"] 7: stretchableImageWithLeftCapWidth:12.0 8: topCapHeight:0.0]; 9: [generateStory setBackgroundImage:pressedImage 10: forState:UIControlStateHighlighted]; 11: 12: [super viewDidLoad]; 13: }
|
In this code block, we’re accomplishing several different things, all focused on providing the button instance (generateStory) with a reference to an image object (UIImage) that “knows” how it can be stretched.
Did you Know?
Why are we implementing this code in the viewDidLoad
method? Because it is automatically invoked after the view is
successfully instantiated from the XIB file. This gives us a convenient
hook for making changes (in this case, adding button graphics) right as
the view is being displayed onscreen.
In lines 2–4 and 6–8, we first
return an instance of an image from the image files that we added to
the project resources. Then we define that image as being stretchable. Let’s break this down into the individual statements:
To create an instance of an image based on a named resource, we use the UIImage class method imagenamed,
along with a string that contains the filename of the image resource.
For example, this code fragment creates an instance of the
whiteButton.png image:
[UIImage imageNamed:@"whiteButton.png"]
Next, we use the instance method stretchableImageWithLeftCapWidth:topCapHeight
to return another new instance of the image, but this time with
properties that define how it can be stretched. These properties are the
left cap width and top cap width, which describe how many pixels in
from the left or down from the top of the image should be ignored before
reaching a 1-pixel-wide strip that can be stretched. For instance, if
the left cap is set to 12, a vertical column 12 pixels wide is ignored
during stretching, and then the 13th column is repeated however many
times is necessary to stretch to the requested length. The top cap works
the same way but repeats a horizontal row to grow the image to the
correct size vertically, as illustrated in Figure 15.
If the left cap is set to zero, the image can’t be stretched
horizontally. Similarly, if the top cap is zero, the image can’t be
stretched vertically.

In this example, we use stretchableImageWithLeftCapWidth:12.0 topCapHeight:0.0 to force horizontal stretching to occur at the 13th vertical column of pixels in and to disable any vertical stretching. The UIImage instance returned is then assigned to the normalImage and pressedImage variables, corresponding to the default and highlighted button states.
Lines 5 and 9–10 use the setBackgroundImage:forState instance method of our UIButton object (generateStory) to set the stretchable images normalImage and pressedImage as the backgrounds for the predefined button states of UIControlStateNormal (default) and UIControlStateHighlighted (highlighted).
This might seem a bit confusing,
and I empathize. Apple has not provided these same features directly in
Interface Builder, despite their usefulness in almost any application
with buttons. The good news is that there is no reason that you can’t
reuse this same code repeatedly in your applications.
Within Xcode, click Build and
Run to compile and run your application. The Generate Story button
should take on a new appearance (see Figure 16).
Remember that despite all of our
efforts to make a pretty button, we still haven’t connected it to an
action. Switch back to Interface Builder to make the connection.
Connecting to the Action
To connect the button to the previously declared createStory
action method, select the button object and open the Connections
Inspector (Command+3) or choose Tools, Connections Inspector. Drag from
the circle beside Touch Up Inside to the File’s Owner icon in the
Interface Builder Document window.
When prompted for a method, choose createStory. The Connections Inspector should update, showing both the outlet that references the button (generateStory) and the createStory method, similar to Figure 17.
At long last, our button is done!