Online Book Reader

Home Category

iOS Recipes - Matt Drance [11]

By Root 269 0
*)offImage

highlightedImage:(UIImage *)highlightedImage;

- (BOOL)toggle;

@end

Since most toggle buttons tend to be image-based, we create a convenience method that abstracts redundant calls to ‑setBackgroundImage:forState:; therefore, our controller code does less work and has fewer potential bugs. It stores the “on” and “off” images in properties, to be used based on the corresponding button state.

ToggleButton/Classes/PRPToggleButton.m

+ (id)buttonWithOnImage:(UIImage *)onImage

offImage:(UIImage *)offImage

highlightedImage:(UIImage *)highlightedImage {

PRPToggleButton *button;

button = [self buttonWithType:UIButtonTypeCustom];

button.onImage = onImage;

button.offImage = offImage;

[button setBackgroundImage:offImage forState:UIControlStateNormal];

[button setBackgroundImage:highlightedImage

forState:UIControlStateHighlighted];

button.autotoggleEnabled = YES;

return button;

}

Note the autotoggle behavior is explicitly set to YES, since BOOL ivars default to NO.

We perform autotoggling by peeking into UIControl’s standard construct for tracking touch events. We do this to find out when the button has received a proper tap; the built-in control logic remains unchanged.

ToggleButton/Classes/PRPToggleButton.m

- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {

[super endTrackingWithTouch:touch withEvent:event];

if (self.touchInside && self.autotoggleEnabled) {

[self toggle];

}

}

The ‑toggle method flips the button’s on property as a convenience; the real work is done in the ‑setOn: accessor method. This is where we switch the default background image based on the managed on/off state.

ToggleButton/Classes/PRPToggleButton.m

- (BOOL)toggle {

self.on = !self.on;

return self.on;

}

ToggleButton/Classes/PRPToggleButton.m

- (void)setOn:(BOOL)onBool {

if (on != onBool) {

on = onBool;

[self setBackgroundImage:(on ? self.onImage : self.offImage)

forState:UIControlStateNormal];

}

}

Adding IB support to this class is trivial. Since IB uses an archiver to load its objects from the nib, the code in +buttonWithOnImage:OffImage: is never executed. So, we implement the ‑awakeFromNib method to properly initialize the autotoggle behavior.

ToggleButton/Classes/PRPToggleButton.m

- (void)awakeFromNib {

self.autotoggleEnabled = YES;

self.onImage = [self backgroundImageForState:UIControlStateSelected];

self.offImage = [self backgroundImageForState:UIControlStateNormal];

[self setBackgroundImage:nil forState:UIControlStateSelected];

}

Using the toggle button from Interface Builder is now a snap. We just drag a Button object from the Library into our parent view, select the Identity inspector, and enter PRPToggleButton as the button’s class. If the class name does not autocomplete this as we type, it’s possible the class was not found. We’ll know for sure when we run the project: if we see Unknown class PRPToggleButton in Interface Builder file in the console, then either the class is missing from the compiled application or its name does not match what we entered in the Custom Class field. We need to check our spelling in both places. Figure 10, Using PRPToggleButton in Interface Builder shows this XIB configuration in Xcode 4.

PRPToggleButton uses the standard button states and background images to manage its on/off state, so we can set those right from IB. Remember to set the custom class in the Identity inspector, or you’ll end up with a plain UIButton.

Figure 10. Using PRPToggleButton in Interface Builder

* * *

Once we’ve configured the class identity, we select the Attributes inspector, where we set our on, off, and highlighted images for the Selected, Default, and Highlighted State Configurations, respectively. There is a small amount of trickery here. Our PRPToggleButton merely switches two images in and out of the Normal control state, but we need a place to put the “on” image in IB. We temporarily use the Selected state for this and then clean up after ourselves in ‑awakeFromNib. Take another look at that code to see how it works.

Run the

Return Main Page Previous Page Next Page

®Online Book Reader