Sunday, November 4, 2012

UITextField with Input from UIPickerView

Sometimes, we need an UITextField whose input is picking from an array of strings. People may popup an UIPickerView from an UIActionSheet/UIPopoverController, but it is easier to use UITextField's inputView to do this. Doing this way is more intuitive and more OOP. I would like to achieve something shown below.

To do this, I created a subclass of UITextField, called PickerTextField

In the header file, we can see it is a direct subclass from UITextField. I created some varibles: 1. sourceStringsArray to hold the array of strings to select from; 2. picker to be the inputView of the TextView. 3. pickedIndex to indicated the selected index.

pickedIndex is also declared as a property, used to be an API from other class to access it. You may wondering, how can we access the text from outside? Super easy. my_sub_class.text will give you the text, just like a normal UITextField.

The method:'{setDataSource: andPlaceHolder:}' is an important method for us to set the sourceStringsArray and the textfield's placeholder property.

First two methods are initialization, they won't be called at the same time. Please refer to the comment in the code. Also note '[super setDelegate:self];', which direct the UITextField's delegate to this subclass itself.

'{setDataSource: andPlaceHolder:}' as mentioned earlier, used to assign sourceStringsArray. It has to be called before using it. Besides, we also setup the picker here, and assign the UITextField's inputView to the picker.

 if (self.pickedIndex!=-1) {
        [self setText:[sourceStringsArray objectAtIndex:self.pickedIndex]];
If you want pre-select certain element for the PickerTextField, you call assign a pickedIndex before calling the method.

The remaining code is quite straight forward. UIPickerView's delegate methods. We change the pickedIndex and the text when the picker's selection changes. The following class is only to serve as the mid-object to forward UITextFieldDelegate methods to the PickerTextField. We pre-select first element, if pickerIndex is not assigned with any value and remains -1. I tried to simply use'[super setDelegate:self]' in PickerTextField, but that will lead to infinite loop, end up have to create the PickerTextFieldHandler class to forward.

You can also download the code from git.