One of my recent projects involved recreating the client’s HTML web form for submitting real estate listings. I’ve spent the past couple of weeks tearing apart methods for handling this within native iOS Apps, and I have to say that I am not impressed with any of the available frameworks. There was one that looked promising called QuickDialog (http://github.com/escoz/quickdialog), and I almost thought that it would fit perfectly. Although the framework seems to be setup nicely, it really doesn’t work well with existing Apps that need the form to be integrated with UI elements such as a UITabBarController, etc. And Storyboard integration is pretty much impossible. I also needed some more complex elements using UICollectionViews for attaching images, which would require tampering with the framework to expand it to fit my needs. Lastly, validation is also non-existant with this framework, and mandatory for my design.
There are tons of other frameworks that you can easily find via a quick Google Search, particularly at http://www.cocoacontrols.com.
After about a day of experimenting with other peoples code, I decided that I need to get my hands dirty and write this thing from scratch. As tempting as it was to start with a UIScrollView and add in my UITextViews and UILabels, I found that using UIScrollViews like this inside Storyboards is an absolute nightmare. My next option, which proved to be the best and most accepted by my more experienced peers, is to use a UITableView.
And so it begins …
There are some UI differences that you will most likely encounter when converting HTML forms, so I thought I would compile a list of all the ones I’ve encountered and my recommended solutions.
<select> to UIPickerView
UIKit does not provide any default UI element that replicates the way HTML <select> elements display options in a web browser (or not that I’m aware of). The best way to handle this in iOS is to create a UIPickerView and assign it to a UITextField’s inputView.
|
1 2 3 4 5 |
_optionsArray = [[NSArray alloc] initWithObjects:@"Option 1", @"Option 2", @"Option 3", @"Option 4", @"Option 5", nil]; _optionsPickerView = [[UIPickerView alloc] init]; _optionsPickerView.delegate = self; _optionsPickerView.showsSelectionIndicator = YES; _optionsTextField.inputView = _optionsPickerView; |
The required delegate methods you’ll need are:
|
1 2 3 4 |
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView; -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component; -(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component; -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component; |
I didn’t find a need for multiple components within simple <select> elements, so you can easily just return 1 for numberOfComponentsInPickerView. For returning the numberOfRowsInComponent, the easiest way is to just use a simple if statement to check for which picker view you’re passing into it, and returning the count for their respective arrays:
|
1 2 3 4 5 6 7 |
if (pickerView == _pickerViewOne) { return _pickerViewOneArray.count; } else if (pickerView == _pickerViewTwo) { return _pickerViewTwoArray.count; } else if (pickerView == _pickerViewThree) { return _pickerViewThreeArray.count; } else return 0; |
Be sure to return 0 if no pickerView is selected, or else it may not return a value and end up breaking your code.
Returning the titleForRow:forComponent: is as simple as above with using an if statement, but instead return the objectAtIndex:row from the respective picker view’s array:
|
1 2 3 4 5 6 7 |
if (pickerView == _pickerViewOne) { return [_pickerViewOneArray objectAtIndex:row]; } else if (pickerView == _pickerViewTwo) { return [_pickerViewTwoArray objectAtIndex:row]; } else if (pickerView == _pickerViewThree) { return [_pickerViewThreeArray objectAtIndex:row]; } else return 0; |
And using the same setup again, when the user makes a selection, didSelectRow:inComponent: will update the respective UITextView.text. This method doesn’t require a return value:
|
1 2 3 4 5 6 7 |
if (pickerView == _pickerViewOne) { _pickerOneTextField.text = [_pickerViewOneArray objectAtIndex:row]; } else if (pickerView == _pickerViewTwo) { _pickerTwoTextField.text = [_pickerViewTwoArray objectAtIndex:row]; } else if (pickerView == _pickerViewThree) { _pickerThreeTextField.text = [_pickerViewThreeArray objectAtIndex:row]; } |
<input type=”radio” …/> to Custom UISwitch
Another form element that I found myself needing was a simple toggle element for defining boolean values. This will also work for <select>’s that simply have a Yes / No option set. These elements can be translated into a custom UISwitch. Apple provides a default “On/Off’ text with the standard UISwitch, but this would make no sense for a lot of my options. Fortunately, you can set a custom image to your UISwitch and simply embed the text within the image.
In accordance with the UISwitch Class Reference, the image size must be 77px wide x 27px tall. Then it’s simply a matter of setting the onImage and offImage properties of your UISwitch.
|
1 2 |
_mySwitch.onImage = [UIImage imageNamed:@"yesImg.png"]; _mySwitch.offImage = [UIImage imageNamed:@"noImg.png"]; |
In the next part(s), I’ll talk more about selecting keyboards, navigation with an accessory view, validation and form submission methods. Feel free to leave questions and comments below.


