Back to Xcode we go once again. Getting dizzy yet? This back and forth may seem a bit strange, but it’s fairly common to bounce around among Interface Builder, Xcode, and the iPhone simulator while you’re developing.
Our application is going to have two switches, which are small controls that can only have two states: on and off. We’ll also add a segmented control to hide and show the switches.
Let’s implement those next.
Determining Outlets
We won’t need an outlet for the segmented control, since we won’t be changing its attri- butes or doing anything with it outside of the action method it calls. We will need some outlets for the switches, however. Since changing the value of either switch will trigger a change in the value of the other switch, we’ll need to change the value of the switch that didn’t trigger the action method, so we won’t be able to rely on using sender. We also need another outlet. We need one for another view that we’re going to add. Remember that we’re going to hide and show these switches and their labels whenever the segmented control is touched.
We could hide each of the items individually, but the easiest way to group multiple controls to hide and unhide them together is to use a UIView as a common parent for the items that need to be hidden or shown together. You’ll see how that works in Interface Builder in a moment, but first, we need to create the outlet for the parent view in addition to the outlets for the two switches.
Determining Actions
The segmented control is going to need to trigger an action method that will hide or show the view containing the switches and their labels. We’re also going to need an action that will fire when either switch is tapped. We’ll have both switches call the same action method, just as we did with the two buttons in Chapter 3. In Control_FunViewController.h, go ahead and add three outlets and two actions, like so:
#import <UIKit/UIKit.h>
#define kSwitchesSegmentIndex 0
@interface Control_FunViewController : UIViewController { UITextField *nameField;
UITextField *numberField;
UILabel *sliderLabel;
UISwitch *leftSwitch;
UISwitch *rightSwitch;
UIButton *doSomethingButton;
}
@property (nonatomic, retain) IBOutlet UITextField *nameField;
@property (nonatomic, retain) IBOutlet UITextField *numberField;
@property (nonatomic, retain) IBOutlet UILabel *sliderLabel;
@property (nonatomic, retain) IBOutlet UISwitch *leftSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *rightSwitch;
@property (nonatomic, retain) IBOutlet UIButton *doSomethingButton;
- (IBAction)textFieldDoneEditing:(id)sender;
- (IBAction)backgroundTap:(id)sender;
- (IBAction)sliderChanged:(id)sender;
- (IBAction)toggleControls:(id)sender;
- (IBAction)switchChanged:(id)sender;
- (IBAction)buttonPressed;
@end
In the code we’ll be writing in a minute, we’re going to refer to a UISegmentedControl prop- erty named selectedSegmentIndex, which tells us which segment is currently selected.
That property is an integer number. The Switches segment will have an index of 0. Rather than stick that 0 in our code, the meaning of which we might not remember a few months from now, we define the constant kSwitchesSegmentIndex to use instead, which will make our code more readable.
Switch over to Control_FunViewController.m, and add the following code:
#import "Control_FunViewController.h"
@implementation Control_FunViewController
@synthesize leftSwitch;
@synthesize rightSwitch;
@synthesize doSomethingButton;
- (IBAction)toggleControls:(id)sender {
if ([sender selectedSegmentIndex] == kSwitchesSegmentIndex) {
leftSwitch.hidden = NO;
rightSwitch.hidden = NO;
doSomethingButton.hidden = YES;
} else {
leftSwitch.hidden = YES;
rightSwitch.hidden = YES;
doSomethingButton.hidden = NO;
} }
- (IBAction)switchChanged:(id)sender {
UISwitch *whichSwitch = (UISwitch *)sender;
BOOL setting = whichSwitch.isOn;
[leftSwitch setOn:setting animated:YES];
[rightSwitch setOn:setting animated:YES];
}
- (IBAction)buttonPressed {
// TODO: Implement Action Sheet and Alert }
- (IBAction)sliderChanged:(id)sender { ...
The first method, toggleControls:, is called whenever the segmented control is tapped.
In this method, we look at the selected segment, and either hide the switches and show the button, or show the switches and hide the button, as appropriate.
The second method we just added, switchChanged:, gets called whenever one of the two switches is tapped. In this method, we simply grab the value of sender, which represents the switch that was pressed, and use that value to set both switches. Now, sender is always going to be either leftSwitch or rightSwitch, so you might be wondering why we’re setting them both. It’s less work to just set the value of both switches every time than to determine which switch called us and only set the other one. Whichever switch called this method will already be set to the correct value, and setting it again to that same value won’t have any affect.
Notice that when we change the value of the switch, we pass a parameter called animated. This lets us specify whether the button should slide over slowly, just as if somebody had pressed it, or if it should just be moved instantly to the new position. We specified
that kind of visual feedback. You can try specifying NO if you want to see the difference, but unless you have good reason, it’s generally a good idea to animate changes made program- matically to the user interface so the user is aware of them.
The third new method, buttonPressed, gets called when the button is pressed. We’re not going to implement this method quite yet, so we added a special comment here to remind ourselves to come back to this method. After typing this special comment, if you select the function method at the top of the editor pane (Figure 4-22), you’ll see that we now have a reminder every time we use the function pop-up that we need to come back here and finish this.
Figure 4-22. Comments that begin with // TODO: will show up on the function pop-up menu at the top of the Editor pane.