In the previous section, we set up our table view controller to display some sample data. Next, we're going to update our UITableViewCell UI by building a custom table view cell.
When we're done, each cell will display's the note's title and last modified timestamp.
Setting a Custom Row Height
Before we create our custom cell, let's adjust the row height for each cell in our table view. This will make the cell height of each of the table view cells taller.
By default, each row, or cell, in a UITableView will have a row height of 44pts.
In Main.storyboard, increase the table view's row height to the following:
Select the UITableView from the Document Outline in your storyboard.
Navigate to the Size Inspector in the Utilities area.
Find the Row Height field and change it's value from 44 to 60.
Making the height of each cell taller gives us a little more room to layout our UI for each note table view cell.
Setting Our Cell UI
With our heighten cells, let's layout our UITableViewCell UI.
Create a vertical stack view with two UILabel on your prototype cell:
Drag two labels from the Object Library onto your blank prototype cell. Make sure to position both labels so that one is above the other.
Select both labels simultaneously. You can do this by selecting one label and shift-clicking on the other label.
Click the Embed In Stack button. If the labels are positioned correct, Interface Builder should create a vertical stack view with the selected label.
Next, we'll set our auto-layout constraints for our stack view.
Set constraints for each edge of the stack view:
Select the stack view using the Document Outline.
Click the Add New Constraints button and add the following constraints:
(Stack View) Top Edge 0pts from Super View (Content View) Top Edge
(Stack View) Leading Edge 15pts from Super View Leading Edge
(Stack View) Trailing Edge 15pts from Super View Trailing Edge
(Stack View) Bottom Edge 0pts from Super View Bottom Edge
Finally, we'll need to add an equal height constraint to our labels to remove some constraint ambiguity.
Set an equal height constraint for both labels within the stack view:
Expand your stack view in your Document Outline.
Select both labels within the stack view.
With both labels selected, click the Add New Constraints button.
In the resulting popup, tick the Equal Heights checkbox and click the Add Constraints button.
Nice! Our cell's UI is coming along. So far you should have the following:
Adding Some Pizzazz
With our cell's layout setup correctly, it's time to add some styling to our labels.
Let's start with the top label.
In Main.storyboard, set the following attributes for the top (note title) label:
Text: Change from Label to Note Title
Font: Change from System 17.0 to System 18.0
Font Color: Change from Black to the hex color #53A8D2
Next, we'll change the attributes for the last modified timestamp label.
In Main.storyboard, set the following attributes for the bottom (last modified timestamp) label:
Text: Change from Label to Last Modified Timestamp
Font: Change from System 17.0 to System 15.0
Font Color: Change from Black to the hex color #67656C
Next, we'll take a look at connecting our storyboard cell to it's corresponding Swift file.
Setting The Cell Custom Class
Already included in your project, in the Views group, is our custom table view cell subclass named ListNotesTableViewCell.
Open ListNotesTableViewCell.swift from your Project Navigator.
Right now, aside from the class definition, your source file should be empty.
Similar to creating a custom subclass our table view controller, to implement a UITableViewCell subclass, we'll first need to set it's corresponding storyboard object's custom class.
In Main.storyboard, set your storyboard prototype cell's custom class:
Select your storyboard table view cell using the Document Outline.
Navigate to the Identity Inspector in the Utilities area.
In the Custom Class section, set the Class attribute to ListNotesTableViewCell. Auto-complete should help you select the correct class.
Next, we'll need to create a way to access the title and last modified labels on our ListNotesTableViewCell class. Without a way to access both labels, we won't be able to set or modified them with code.
Sound familiar? IBOutlet to the rescue!
Creating Cell IBOutlets
We'll need to create a corresponding IBOutlet for each of our custom cell's labels. This will allow us to set and access each label programmatically.
Let's start by creating an IBOutlet for our note title label.
First start by opening the Assistant Editor:
Open Main.storyboard from your Project Navigator.
Click on the Show the Assistant Editor button in the tool bar.
(Optionally) Hide both the Navigator and Utilities panes to create more screen space for the Assistant Editor.
(Troubleshooting) If you don't see the ListNotesTableViewCell.swift file show up in the second editor window, change the Assistant Editor file by selecting Manual > MakeSchoolNotes > MakeSchoolNotes > Views > ListNotesTableViewCell.swift in the dropdown above.
With our Assistant Editor displaying storyboard file and ListNotesTableViewCell.swift source code side-by-side, we can create each label's IBOutlet.
Create a IBOutlet for each corresponding label:
For each label:
Select the label within the stack view using the Document Outline.
Control-click from the label to the ListNotesTableViewCell class definition in the Assistant Editor.
Name the IBOutlet accordingly:
Title Label: noteTitleLabel
Last Modified Timestamp: noteModificationTimeLabel
When you're done, you can exit the Assistant Editor and switch back to the Standard editor.
With our new IBOutlet connections, we're now able to access each label property in our ListNotesTableViewCell!
Type Casting Our Cell
Before we move on, we need to make one additional change to table view data source code.
Open ListNotesTableViewController.swift. Take another look at our current implementation of tableView(_:cellForRowAt:).
In the code above, our code uses dequeueReusableCell(withIdentifier:for:) to retrieve the appropriate table view cell. The string identifier we've provided as a parameter, matches the Identifier in our storyboard's Identifier attribute.
However, our code doesn't know that our storyboard cell has a custom class of ListNotesTableViewCell.
Right now our code thinks cell has the default UITableViewCell type.
Option-click on the cell constraint. You should see the following:
Since Swift is statically-typed, we can option-click on constants/variables and the compiler will show a popup with the current type of cell.
To change this, we'll need to use type casting to tell our code that the cell from the identifier has a custom class of ListNotesTableViewCell.
In ListNotesTableViewController.swift, downcast the cell in tableView(_:cellForRowAt:) to the correct custom class.
In the code above, we type cast our cell constant by using the as keyboard with the force unwrap optional !, followed the custom class we want type cast to, in this case, ListNotesTableViewCell. This is referred to as downcasting.
Be careful when downcasting! If the storyboard cell doesn't have it's custom class set to the type you're force casting to, this code will crash your app!
After type casting our cell, you can option-click on our cell constant to see that the type has changed from UITableViewCell to ListNotesTableViewCell.
Now that our cell has the correct type, we can also access the ListNotesTableViewCell properties. Let's set both labels that we created an IBOutlet for.
In ListNotesTableViewController.swift, update the method tableView(_:cellForRowAt:) to set each of the labels: