Reacting to a Picker View Choice
For our application to
respond to a user touching and changing the value within one of the
picker components, we need to implement another method within the UIPickerViewDelegate protocol: pickerView:didSelectRow:inComponent.
This method is called when the user changes something in the picker
view—as part of the parameters, we get back a reference to the picker
itself, the row number that was selected, and which component number it
was in.
Do you see any problem with that? Although the method certainly tells us when something was picked, and what
was picked, it only gives us the value for the picker component that
the user was changing. In other words, we’ll get back the chosen animal
name but not the sound (or vice versa).
To access the value of any picker component at any time, we can use the UIPickerView instance method selectedRowInComponent. This returns the currently selected row in whatever component number we pass to it. If we have a reference to our picker in pickerView, for example, we could retrieve the selected animal name row like this:
[pickerView selectedRowInComponent:animalComponent]
By the Way
Hopefully it’s starting
to become obvious why it makes sense to use constants to keep track of
the component numbers. Being able to use animalComponent or soundComponent directly in the code makes it much easier to read, and, long term, easier to maintain.
With all this information in hand, we’re ready to write and review the pickerView:didSelectRow:inComponent method. Add the code in Listing 6 into MatchPickerViewController.m.
Listing 6.
1: - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row 2: inComponent:(NSInteger)component { 3: NSString *actionMessage; 4: NSString *matchMessage; 5: int selectedAnimal; 6: int selectedSound; 7: int matchedSound; 8: 9: if (component==animalComponent) { 10: actionMessage=[[NSString alloc] 11: initWithFormat:@"You selected the animal named '%@'", 12: [animalNames objectAtIndex:row]]; 13: } else { 14: actionMessage=[[NSString alloc] 15: initWithFormat:@"You selected the animal sound '%@'", 16: [animalSounds objectAtIndex:row]]; 17: } 18: 19: selectedAnimal=[pickerView selectedRowInComponent:animalComponent]; 20: selectedSound=[pickerView selectedRowInComponent:soundComponent]; 21: 22: matchedSound=([animalSounds count]-1)- 23: [pickerView selectedRowInComponent:soundComponent]; 24: 25: if (selectedAnimal==matchedSound) { 26: matchMessage=[[NSString alloc] initWithFormat:@"Yes, a %@ does go '%@'!", 27: [animalNames objectAtIndex:selectedAnimal], 28: [animalSounds objectAtIndex:selectedSound]]; 29: } else { 30: matchMessage=[[NSString alloc] initWithFormat:@"No, a %@ doesn't go '%@'!", 31: [animalNames objectAtIndex:selectedAnimal], 32: [animalSounds objectAtIndex:selectedSound]]; 33: } 34: 35: lastAction.text=actionMessage; 36: matchResult.text=matchMessage; 37: 38: [matchMessage release]; 39: [actionMessage release]; 40: 41: }
|
Lines 3–4 kick off the implementation by declaring two strings, actionMessage and matchMessage,
which will be used to hold the contents of the messages that we’ll be
displaying to the user to view the labels in the interface.
Lines 5–7 define three integers (selectedAnimal, selectedSound, and matchedSound)
that we’ll be using to hold the currently selected animal and sound and
the “fixed” number of the currently selected sound. Recall that the
sound and animal rows don’t match up numerically? We’ll use the matchSound
variable to hold the results of the calculation that determines whether
the sound the user has chosen matches the correct animal.
Lines 9–17 allocate and initialize a string, actionMessage, which describes what the user has done. If the component provided to the method is the animalComponent, the string will contain a message stating that they chose an animal. It will also identify the animal via the row variable and the animalNames
array. If they choose a sound, the message and logic will be
appropriate to that action instead. We’re using the same techniques
implemented earlier to populate the picker’s display.
Lines 19–20 use the selectedRowInComponent method to retrieve the currently selected rows in the animal and sound components. The results are stored in the selectedAnimal and selectedSound variables, respectively.
Lines 22–23 work the magic of calculating if the chosen sound matches the chosen animal. The matchedSound value will equal the selectedAnimal value if the user has picked a match. You can refer to the earlier section “Populating the Data Structures” for help understanding the math—it isn’t critical in understanding the picker view itself.
Lines 25–33 compare selectedAnimal to matchedSound.
If they are equal, the user has chosen correctly, and an appropriately
congratulatory message is created and stored in the string matchMessage. If users make an incorrect choice, they’re informed of the error with a slightly different message. In either case, the matchMessage string includes both the name of the animal and the sound so that users complete feedback about what they’ve selected.
Lines 35–36 output the actionMessage and matchMessage to the user by setting the text properties of the lastAction and matchResult labels.
Lines 38–39 release the two strings, matchMessage and actionMessage, allocated and initialized in the method.
Save your updated
implementation file, and choose Build and Run. Scroll through the
animals and sounds and make your choices. As you change the selection in
the picker view, the messages should update accordingly, as Figure 7 shows.