How to create an input form using UITableView

UITableView is a powerful UI element that is used in various scenarios of iOS application development.

In this article we will learn how to use it to build UI for input forms. When we finish implementation, we will have something similar to this:

Final input form using UITableView

Let’s get started

Create a Single View Application project, open Main.storyboard and delete view controller that is already there. Delete ViewController.swift file as well.

Drag and drop Table View Controller on the storyboard’s surface and make it initial view controller using Attribute Inspector:

Attribute Inspector: Is Initial View Controller

UITableView can contain dynamic or static cells. We need the second one to build an input form:

Attribute Inspector: Static Cells

Go to Document Outline and delete all table view cells except the first one.

Design Table Cell

Label, View and Text Field

Now we can design our cell. Later we will copy/paste it to create more table cells with the same visual appearance.

Drag and drop one Label, one View and one Text Field on the cell’s surface. Set background color of the View to #CCCCCC, and Alpha to 0.5. Reorder and change sizes of UI elements to correspond to the image below:

Interface Builder: Label

Select Table View Cell in the Document Outline and set its background to #FCFFE1, Then select the Label and set its font to Caption 1 and its color to #42AEDD. Set its alignment to Right. Now select the Text Field and set its border style to None. Finally, set its font to Body.

You should have something similar to this now:

Interface Builder: Customize colors and fonts of the table view cell

Auto Layout

Let’s add Auto Layout  constraints to the UI elements inside this cell.

Label

Select label and click on Pin button. Set constraints as shown in the screenshot below:

Auto Layout constraints for the Label

View

Select view and click on Pin button. Set constraints as shown in the screenshot:

Auto Layout constraints for the View

Text Field

Now add constraints to the text field as shown in the screenshot:

Auto Layout constraints for the Text Field

Update Frames

Click on Resolve Auto Layout Issues button and select Update Frames menu item to make Interface Builder re-layout UI elements according to added Auto Layout constraints:

Resolve Auto Layout Issues: Update Frames

Now our table view cell should look like this:

Table View Cell: Auto Layout constraints in action

Design Personal Info Section

Select Table View and set its style to Grouped:

UITableView: Grouped Style

This will make table view to show sections. Now select Table View Section in the Document Outline and set its Header property to Personal Info.

Select Table View Cell in the Document Outline and copy paste it four times. Now you should have five rows in the Personal Info section. Update text of labels inside these rows to values from the following list:

  1. Nickname

  2. First Name

  3. Last Name

  4. Password

  5. Password (again)

Then select all table view cells and click on Update Frames. Now you should have something like this:

Table View: Personal Info section

If labels' fonts are different after the Copy/Paste - just close and reopen Xcode. This should fix the issue.

Design Contact Info Section

Copy and paste previous section, change text, remove extra rows, update frames. This is how your table view should look like:

Table View with all sections

Make Labels to Have the Same Width

As you noticed, all labels have different widths and because of that vertical lines have different positions. There is a special Auto Layout constraint called Equal Widths:

Auto Layout: Equal Widths

This constraint makes all selected items to have the same width. Unfortunately, it’s not possible to apply it to the UI elements, that have different root views.

However it is possible to fix this in code:

  1. Find label with the highest width value.

  2. Add Auto Layout constraints to all labels to have exactly this width.

Create new Cocoa Touch Class, and inherit it from UITableViewController. Call it TableViewController. Then select Table View Controller in the storyboard and set its class to TableViewController in the Identity Controller.

Go back to the TableViewController class and remove all methods from it.

The following method calculates label’s width:

private func calculateLabelWidth(label: UILabel) -> CGFloat {
    let labelSize = label.sizeThatFits(CGSize(width: CGFloat.max, height: label.frame.height))

    return labelSize.width
}

I use  sizeThatFits(_:) method of the UIView class to calculate size of the UILabel.

The next step is to find maximum width of labels:

private func calculateMaxLabelWidth(labels: [UILabel]) -> CGFloat {
    return reduce(map(labels, calculateLabelWidth), 0, max)
}

The next method adds Auto Layout constrains to constrain label widths:

private func updateWidthsForLabels(labels: [UILabel]) {
    let maxLabelWidth = calculateMaxLabelWidth(labels)
    for label in labels {
        let constraint = NSLayoutConstraint(item: label,
                                       attribute: .Width,
                                       relatedBy: .Equal,
                                          toItem: nil,
                                       attribute: .NotAnAttribute,
                                      multiplier: 1,
                                        constant: maxLabelWidth)
        label.addConstraint(constraint)
    }
}

Now we need list of labels to apply this method to. Add outlet collection property:

@IBOutlet var labels: [UILabel]!

And link it with all labels on the input form:

Connect outlet collection with all labels

Update widths in viewDidLoad:

override func viewDidLoad() {
    updateWidthsForLabels(labels)
}

Compile and run:

Input Form based on UITableView

The End

That’s it. I hope that was useful.