How To Make a Gesture-Driven To-Do List App Like Clear in Swift: Part 1/2

Learn how to make a gesture-driven to-do list app like Clear, complete with table view tricks, swipes, and pinches. By Audrey Tam.

Leave a rating/review
Save for later
Share

Learn how to make a stylish gesture driven to-do app like Clear!

Learn how to make a stylish gesture driven to-do app like Clear!

Update 04/21/2015: Updated for Xcode 6.3 and Swift 1.2.

Update note: This tutorial was fully updated for iOS 8 and Swift by Audrey Tam. Original post by Tutorial Team member Colin Eberhardt. Updated December 9 2014 for Xcode 6.1.1.

This two-part tutorial series will take you through the development of a simple to-do list app that is free from buttons, toggle switches and other common user interface (UI) controls.

Instead, users will interact with your app via a set of intuitive gestures, including swipes, pull-to-add, and pinch. In eschewing the common interface components, you’ll present the user with a more striking and clutter-free interface. It’s not an empty gesture!

This tutorial is for intermediate or advanced developers – you will be doing some tricky things like working with gradient layers, performing animations, and creating a custom table view cell. If you are a beginner developer, you should start with some of our other tutorials.

If you want to make better use of gestures in your application, then this is the tutorial for you. Read on to start the hand aerobics!

Skeuomorphism and Touch Interfaces

Before diving into the code, it’s worth taking some time to discuss the role of gestures in UI design. Don’t worry – it’s a “gripping” topic!

The mobile multi-touch interface allows for much more direct interaction – and therefore much more control and expression – than does a simple mouse pointer device.

Some very cool and intuitive gestures have been developed, such as pinch/stretch, flick, pan, and tap-and-hold. But they are rarely used! (One notable exception is the pinch/stretch, which has become the standard mechanism for manipulating images.)

Despite the expressive nature of touch, we developers still fall back on the same old UI paradigms of buttons, sliders, and toggle switches. Why?

One of the reasons we continue to use these same-old UI components is due to a design philosophy known as skeuomorphism.

Ragecomic

To help users understand a visual computer interface, we design UIs to look like physical objects that the user is already familiar with. For years, we designed buttons on an iPhone screen to look like buttons in the physical world because users already know how to push buttons. Until the release of iOS 7 in the fall of 2013, Apple thoroughly embraced skeuomorphic design in its own applications, achieving almost photo-realistic representations of physical objects, such as notebooks and bookshelves.

But hey – designs can evolve as readily as technology. With iOS 7, Apple moved drastically away from skeuomorphism, removing many of the shadows and borders reminiscent of the physical world. In addition, the user experience was built around gestures more than ever before: swipe up from the bottom of the screen to reveal Control Center replaced the home button double tap. Swipe right from the left edge is encouraged over the Back button. As Apple embraces gestures in their user experience, it’s time to consider how to use gestures in our own apps.

I thoroughly recommending watching Josh Clarke’s presentation “Buttons are a Hack”, wherein he encourages developers to think more creatively about gestures and touch interactions. The next time you go to add a new control to your interface, ask yourself, “Can I perform the same function via touch?”

When an application comes along that makes good use of gestures, it is quite striking. A recent example is Clear by Realmac software. Be sure to check out the great demo on YouTube, or even better download the app to check it out.

This tutorial describes the development of a to-do list application that is very similar to Clear. The purpose of this tutorial is to encourage you to think about how to make better use of gestures in your own applications, rather than to create a clone of Clear. I encourage you to download and buy Clear, as it is a truly inspirational app.

Anyhow, I think it’s time I climbed down from my soapbox and showed you all some code!

Overview

There are several steps in this tutorial, so it might be helpful to see the overall plan before you begin. You’ll be completing 7 checkpoints:

  1. You’ll start by creating a basic UITableView with a UIViewController named ViewController that conforms to UITableViewDataSource protocol, displaying a hard-coded list of ToDoItems.
  2. Then you’ll set ViewController to conform to UITableViewDelegate protocol, and implement UITableViewDelegate methods to modulate row color from red to yellow.
  3. To fine-tune the “look”, you’ll create a custom UITableViewCell named TableViewCell, where you’ll implement a gradient effect within each table row.
  4. The first gesture you’ll implement is swipe-left-to-delete, and the first step is to add a UIPanGestureRecognizer to TableViewCell, and detect this delete gesture.
  5. TableViewCell needs to delegate the actual deletion from ToDoItems, so you’ll create a protocol named TableViewCellDelegate for ViewController to adopt
  6. Next, you’ll handle swipe-right-to-complete, which layers a strikethrough over the row text, and also changes the row color to green: you’ll implement this by writing a custom UILabel named StrikeThroughText.
  7. As a final polish, you’ll implement TableViewCell properties crossLabel and tickLabel, to display contextual cues while the user is swiping left or right. They’ll change color (red cross for delete, green tick for complete) when the user has dragged the row far enough left or right.

Getting Started

This first Checkpoint is just a basic table of to-do items so, if you’re already comfortable with doing that, download this starter project and skip down to Styling Your Cells

If you want some practice, fire up Xcode and create a new iPhone application by going to File\New\Project, selecting the iOS\Application\Single View Application template and tapping Next. On the next screen, enter ClearStyle as the product name, and fill in the other details similar to the image below:

NewProject

The standard approach to rendering scrollable lists within an iPhone application is to use a UITableView, so you’ll add a Table View to the storyboard view and connect it to an outlet in the view controller that was created in the project template.

Open Main.storyboard and drag a Table View onto the scene (view), positioning it so that it covers the whole scene:

StoryboardTableView

To ensure tableView always takes up the entire screen, pin its top, bottom, left and right edges to be 0 points from the parent view.

Next, connect the Table View to an outlet in ViewController.swift: show the Assistant Editor, select the Table View, control-drag from it into ViewController.swift, just inside the class block, and name the outlet tableView:

StoryboardOutlet

Delete the didReceiveMemoryWarning method.

Note:The eagle-eyed among you might be wondering why I used a UITableView within a UIViewController – why not use a UITableViewController? Well, I originally wrote this with a UITableViewController and everything worked fine until the very last step of Part 2, when it became unstable. The version I wrote with a UIViewController still worked well, so it’s possible there’s a subtle bug in Swift.

A to-do list is essentially a list of items rendered on the screen, so you need to create an object that represents each to-do item. In the Project Navigator, right-click ViewController.swift and select New File…, then select the iOS\Source\Cocoa Touch Class template and add a class called ToDoItem. Make it a subclass of NSObject, set Language to Swift, but don’t create a XIB file:

AddToDoItemClass

Open ToDoItem.swift and add two properties and an init method (between the curly braces { }):

// A text description of this item.
var text: String

// A Boolean value that determines the completed state of this item.
var completed: Bool

// Returns a ToDoItem initialized with the given text and default completed value. 
init(text: String) {
    self.text = text
    self.completed = false
}

A to-do item is simply a string of text and a Boolean that indicates whether the item is completed or not.

Note: Selecting a file in the Project Navigator before you create a New File causes Xcode to place the new file just below the file that you selected.

Open ViewController.swift and, in viewDidLoad, declare and initialize the toDoItems array:

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    var toDoItems = [ToDoItem]()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if toDoItems.count > 0 {
            return
        }
        toDoItems.append(ToDoItem(text: "feed the cat"))
        toDoItems.append(ToDoItem(text: "buy eggs"))
        toDoItems.append(ToDoItem(text: "watch WWDC videos"))
        toDoItems.append(ToDoItem(text: "rule the Web"))
        toDoItems.append(ToDoItem(text: "buy a new iPhone"))
        toDoItems.append(ToDoItem(text: "darn holes in socks"))
        toDoItems.append(ToDoItem(text: "write this tutorial"))
        toDoItems.append(ToDoItem(text: "master Swift"))
        toDoItems.append(ToDoItem(text: "learn to draw"))
        toDoItems.append(ToDoItem(text: "get more exercise"))
        toDoItems.append(ToDoItem(text: "catch up with Mom"))
        toDoItems.append(ToDoItem(text: "get a hair cut"))
    }

Next, add the required UITableViewDataSource methods:

// MARK: - Table view data source

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return toDoItems.count
}

func tableView(tableView: UITableView,
    cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", 
            forIndexPath: indexPath) as! UITableViewCell
        let item = toDoItems[indexPath.row]
        cell.textLabel?.text = item.text
        return cell
}

Then declare that ViewController conforms to UITableViewDataSource and UITableViewDelegate protocols:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

And finish configuring tableView in viewDidLoad by adding these lines just below super.viewDidLoad:

tableView.dataSource = self
tableView.delegate = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")

And with that, Checkpoint 1 is done! Set the active scheme to iPhone 5, build and run your code, and you will be presented with the wonderfully minimalist to-do list shown below:

ToDoListFirstCut

Contributors

Over 300 content creators. Join our team.