Gmail is my favorite email application. It’s grown massively over the years and is the default for many users. I’ve used it personally and at many different companies.
For a lot of people, its one of the first screens you see every morning for work.
Let’s see how they build their main view:
I recommend downloading the starter project here or you can create a new project from blank in Xcode. If you start your own project from blank in Xcode, read this article on how to remove storyboards.
Change the bundle identifier to something unique.
Next select your preferred development team (personal for most people).
Run and build your app, it will look like this:
This app currently doesn’t do anything. We’re going to be building each of the controls step by step.
I’ve drawn a red box around most of the main UI elements that we’ll build in this article. The other elements will be covered in another article.
From looking at the Gmail application, the main view appears to be one large table view. Let’s start by building that. Open up your MainViewController.xib
.
Here we’ll add a table view by open up the Object Library by either using the keyboard shortcut CMD + Shift + L or by clicking the square within a circle in the top right corner.
Once you have that dialog open, search for table.
Drag the table view into your view and expand it so the corners fill the view.
Now add constraints to the table view so that it is pinned to the superview. To do this, select the table view and the click the tie-fighter icon in the bottom right. Click on all four constraints and set them to zero.
This way your table view will be pinned to the edges, no matter what screen size it is on.
Go into your main view controller and add an IBOutlet for your table view now. To do this click on the table view, hold ctrl, click and drag it into your Swift file.
@IBOutlet weak var tableView: UITableView!
Now create a viewDidLoad
function:
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.separatorStyle = .none
}
Xcode will give you an error here and demand that this class be of type UITableViewDataSource
and UITableViewDelegate
. So create an extension just underneath this class to fulfill these requirements.
extension MainViewController: UITableViewDataSource, UITableViewDelegate {
}
Let’s leave this extension empty for now.
The next step is to create a custom table cell for your table view.
Create a new Cocoa Touch Class by going to File > New File or with keyboard shortcut CMD+N. Select the Cocoa Touch Class:
Be sure to subclass UITableViewCell
and check Also Create Xib
.
Open up your table view cell xib and search for label in your object library. You can open up the object library by clicking the square within a circle icon in the top right. Or by using keyboard short CMD + Shift + L.
Position your first label like so:
This will be the from address line. Here are my font settings that you can access when you click the Attribute Inspector (CMD + Option + 4).
Next create another label for the email subject line.
Here are my settings for this label:
Lastly create a label for an excerpt of the email:
These are my settings for the email excerpt, I am using the color #7B7B7B for the text:
Lastly we have to add the circle icon we see in Gmail. To do this, we’ll create an image view and drag it into place. Grab an image view from the object library (CMD + Shift + L) and put it to the left of the text.
Now let’s add constraints to lock all these positions in place. To add constraints click on an element, hold CTRL and then drag to another element.
For the sender line (“Credit King Tax”), I added these constraints.
You can view all constraints on an element by selecting it and then opening its Size Inspector
(keyboard shortcut: CMD+Option+5)
For the subject line (“Get Ready For Tax Season”), I added these constraints:
For the email excerpt line (“File your taxes for free”) I added these constraints:
For the image view I added these constraints:
To add height and width constraints, remember to click the tie-fighter icon in the bottom right hand corner.
For the image, I’ve made a circle image in Photoshop to paste in here.
Add this to your Assets.xcassets
and set your image to this.
So all together our table cell should look like this in the XIB:
We need to set our cell height correctly. Go to the Size Inspector
of your table cell view and set it to 75.
Now we’ll have to set the same height in our table view. Open up MainViewController.xib
, select the table view and go to the Size Inspector
. Set the cell height to the same value 75.
It’s nice that we have one email, but what do we do when we have multiple emails? Let’s create an email model swift file. A model is a representation of the information required to build an email cell.
Create a Swift new file (CMD + N) and name it EmailModel.swift
. In this empty file, we’ll create a class named EmailModel.
class EmailModel {
}
Let’s think about what properties we want this class to have. We know all of our emails have the following:
So let’s add these elements to our class:
import Foundation
import UIKit
class EmailModel {
let sender: String
let senderProfileImage: UIImage
let subjectLine: String
let emailExcerpt: String
var starred: Bool
}
I also had to add import UIKit
since the type UIImage
is in there. You’ll notice I made most of the properties constants with the let
keyword. I made starred
a variable, since the user can star and unstar emails.
Now let’s create a constructor for this class:
init(sender: String, senderProfileImage: UIImage, subjectLine: String, emailExcerpt: String, starred: Bool) {
self.sender = sender
self.senderProfileImage = senderProfileImage
self.subjectLine = subjectLine
self.emailExcerpt = emailExcerpt
self.starred = starred
}
In our main view controller we can create some email model instances:
let emails = [
EmailModel(sender: "The Tax Man", senderProfileImage: UIImage(named: "person1")!, subjectLine: "Time to file taxes!", emailExcerpt: "Completely free", starred: true),
EmailModel(sender: "Cool Gym", senderProfileImage: UIImage(named: "person2")!, subjectLine: "Awesome gym deal!", emailExcerpt: "No sign up fee this week", starred: false),
EmailModel(sender: "Discount Clothes", senderProfileImage: UIImage(named: "person3")!, subjectLine: "New summer styles", emailExcerpt: "50% off everything!", starred: false),
]
Now we three demo emails to test our app. In a later tutorial, we’ll learn how to pull this information from a backend database.
So how do we get these emails into our user interface?
Open up EmailTableViewCell
and clear it out.
import UIKit
class EmailTableViewCell: UITableViewCell {
}
Now open up the EmailTableViewCell.xib
in your assistant editor by holding Option and clicking on it.
Now we’re going to add multiple IBOutlets to our EmailTableViewCell.swift
. To do this, hold ctrl, then click and drag each of the elements over.
You should have all the elements as IBOutlets in your Swift file now:
class EmailTableViewCell: UITableViewCell {
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var sender: UILabel!
@IBOutlet weak var subjectLine: UILabel!
@IBOutlet weak var emailExcerpt: UILabel!
}
Let’s also add a reference to the EmailModel as a property of this view cell.
var emailModel: EmailModel?
Now let’s create a function that allows us to set these up using an EmailModel
.
func setEmailModel(emailModel: EmailModel) {
self.emailModel = emailModel
}
Modify our emailModel property to set up the view properly when it’s set:
var emailModel: EmailModel? {
didSet {
guard let emailModel = emailModel else { return }
senderProfileImage.image = emailModel.senderProfileImage
sender.text = emailModel.sender
subjectLine.text = emailModel.subjectLine
emailExcerpt.text = emailModel.emailExcerpt
}
}
Awesome - that’s it for our EmailTableViewCell.swift
.
Let’s go back to our main view controller and setup the table view correctly.
Fill in our extension:
extension MainViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return emails.count
}
}
This tells our table view how many rows it will have. We set it to number of emails in the emails
array.
Next we’ll build each cell:
extension MainViewController: UITableViewDataSource, UITableViewDelegate {
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("EmailTableViewCell", owner: self, options: nil)![0] as! EmailTableViewCell
cell.setEmailModel(emailModel: emails[indexPath.row])
return cell
}
}
This returns our custom cell set with the proper email model for each row. We first load it from it’s Nib, then set the model. Finally we return it.
Run your app now (CMD+R)!
Now that we’ve got the basic email user interface completed, let’s add some user interaction. A popular feature of Gmail is the ability to star an email.
Let’s add a star icon to each of the email rows. Open up your EmailTableViewCell.xib
file. Search for a button in the Object Library (CMD + Shift + L), then select the button. Drag it onto your cell view to the top right hand corner.
Now open up your attribute inspector and set the buttons image to a star border. Download the star images here.
I’ll also add some constraints to this button in order to lock it into place and set its size.
Run your app (CMD + R) and it should look like this:
We have star button, but it doesn’t do anything. Let’s make this button work!
Open up your EmailTableViewCell.swift
and your corresponding .xib
in your assistant editor (hold option and click on it). Create an IBOutlet
for your button by holding ctrl and click-dragging it into your Swift file.
@IBOutlet weak var starButton: UIButton!
Create a IBAction
by clicking on your button in your xib and opening up its Connections Inspector
(CMD + Option + 6). Drag Touch Up Inside
into your code.
@IBAction func starButtonPressed(_ sender: UIButton) {}
Let’s add some logic to change this button image.
@IBAction func starButtonPressed(_ sender: UIButton) {
guard let emailModel = emailModel else { return }
emailModel.starred = !emailModel.starred
let starImage = emailModel.starred ? UIImage(named: "star-yellow") : UIImage(named: "star-border")
starButton.setImage(starImage, for: .normal)
}
The above function does the following:
Run your app now (CMD + R):
Clicking the star buttons will work!
One more thing we need to do is update our didSet
in our emailModel property to include the button.
var emailModel: EmailModel? {
didSet {
guard let emailModel = emailModel else { return }
senderProfileImage.image = emailModel.senderProfileImage
sender.text = emailModel.sender
subjectLine.text = emailModel.subjectLine
emailExcerpt.text = emailModel.emailExcerpt
let starImage = emailModel.starred ? UIImage(named: "star-yellow") : UIImage(named: "star-border")
starButton.setImage(starImage, for: .normal)
}
}
So now if an email has been starred before, the star button will be set to the correct image.
Sliding to archive or delete is one of the most used features of the Gmail app. In iOS 11, Apple introduced a couple of methods to make this a lot easier. Open up your MainViewController.swift
and go to your extension.
In your extension add a trailingSwipeActions
function like so:
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (action, view, handler) in
self.emails.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
handler(true)
}
deleteAction.backgroundColor = UIColor(red:0.24, green:0.49, blue:0.25, alpha:1.0)
deleteAction.image = UIImage(named: "archive")
let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
configuration.performsFirstActionWithFullSwipe = true
return configuration
}
You can download the archive icon image here.
This won’t produce the exact same animation as the Gmail app, but it’s a good starting point. Run your application and you should see this.
That’s it for now, but stay tuned for the next article in this tutorial.
The Complete iOS App Development Bootcamp
Disclosure: This website may contain affiliate links, meaning when you click the links and make a purchase, we receive a commission.