UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

How to add peek and pop to a UITableView

Swift version: 5.6

Paul Hudson    @twostraws   

Peek and pop are features of 3D Touch that let users press hard on something to show more information. It’s surprisingly easy to add when working with table view cells and collection view cells, and downright trivial if you use storyboards and segues.

First, the trivial case: if you’re using storyboards and segues, Xcode can do all the work for you. If you want to see how easy it is, create a new iOS app using the Master-Detail project template, then open Main.storyboard. Find the Show Detail segue that moves from the table view to the detail view, then check the box marked “Preview & Commit Segues” in the attributes inspector.

That’s it: iOS will automatically make peek and pop code for that segue – you can press hard on a table view cell to bring up the detail controller as a preview, then press harder to make it full screen. (Note: if you’re using the simulator this isn’t easy to do – try using a real device!)

If you’re not using segues you need to write some code yourself. First, make your view controller conform to UIViewControllerPreviewingDelegate so that you’re able to respond to previewing requests correctly. Second, you need to tell the system we want to support previewing by calling registerForPreviewing() in your viewDidLoad() method:

registerForPreviewing(with: self, sourceView: yourTableView)

That tells iOS that the view controller is able to respond to previewing requests for your table view.

There are two methods you need to fill in for the UIViewControllerPreviewingDelegate protocol: which view controller should be shown when the user presses at a certain location, and when the user presses harder how do you want to present it.

For many apps the code to create a previewing detail controller will be the same code to create a regular detail view controller, so it’s a good idea to create a method to instantiate a detail view controller and configure it as needed.

For example, you might have something like this:

func detailViewController(for index: Int) -> DetailViewController {
    guard let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController else {
        fatalError("Couldn't load detail view controller")
    }

    vc.selectedItem = index
    return vc
}

You would then have something like this inside your didSelectRowAt method:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let vc = detailViewController(for: indexPath.row)
    navigationController?.pushViewController(vc, animated: true)
}

Now for the important part: filling in the peek and pop methods.

You need to write a viewControllerForLocation method, which gets called with whatever location on the screen the user touched. You can pass that straight to the table view to ask it what row is at that location, then tell the previewing context to use that row as its source rect – iOS will cause that row to zoom up while the others get blurred. Finally you can return the correct view controller, but if no cell was tapped you need to return nil instead so that no 3D Touch effect happens.

Here’s how that looks in code:

func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
    if let indexPath = yourTableView.indexPathForRow(at: location) {
        previewingContext.sourceRect = yourTableView.rectForRow(at: indexPath)
        return detailViewController(for: indexPath.row)
    }

    return nil
}

As for the pop effect, that’s just one line of code inside a commit method. You’ll be given the view controller that’s currently being peeked, so your method just needs to decide how to present it. For example, if you’re using a navigation controller you probably want to call pushViewController() here – iOS will automatically convert that into a pop zoom animation with bounce effect, but the end result will be a pushed view controller so you can go back like normal.

Here’s that in Swift:

func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
    navigationController?.pushViewController(viewControllerToCommit, animated: true)
}

That’s all the code – it’s not really that hard to do, and UIKit makes the result look great.

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Available from iOS 9.0

Similar solutions…

About the Swift Knowledge Base

This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.6/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.