With iOS 9, new iPhone models add a third dimension to the user interface, called force touch, or more commonly 3D Touch.

A user can now press your Home screen icon to immediately access functionality provided by your app. Within your app, a user can now press certain views to see previews of additional content and gain accelerated access to features.

Peek and Pop

iOS 9 lets you configure view controllers to allow the use of peek, which provides a preview of additional content when a user presses on a specified view, and pop, which commits to viewing that content and navigates to it.

This interaction proceeds through three phases.

  1. Indication that content preview is available
  2. Display of the preview, known as a peek, with options to act on it directly, known as peek quick actions
  3. Optional navigation to the view shown in the preview, known as a pop

Setup

Lets imagine that we have 2 UIViewControllers in our app. One has a UICollectionView as its main UI, for example to show a list of images, we shall call it ImageViewController. The other one is a DetailViewController that will be presented if one of the images is pressed. This should be a very common scenario in most apps.

If we want to use Peek and Pop we first have to check wether 3D touch is supported and if it is, register the previewing delegate.

class ImageViewController: UIViewController {

  override func viewDidLoad() {
      super.viewDidLoad()

      // Do your usual setup
      ...

      // Register peek and pop if available
      guard traitCollection.forceTouchCapability == .available else { return }
      registerForPreviewing(with: self, sourceView: view)
    }   
}

Implement The Delegate

Next we need to implement the above registered delegate, called UIViewControllerPreviewingDelegate. This delegate has 2 methods, 1 for peeking and 1 for popping.

class ImageViewController: UIViewController {
    ...
}

// MARK: - UI View Controller Previewing Delegate

extension ImageViewController: UIViewControllerPreviewingDelegate {

    /// Peek
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {

      // Get the index path of the cell we are force touching on
      guard let indexPath = collectionView.indexPathForItem(at: location) else { return nil }

      // Get the actual cell instance for the index path
      guard let cell = collectionView.cellForItem(at: indexPath) else { return nil }

      // Instantiate the detail view controller
      guard let detailVC = storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as? DetailViewController else { return nil }

      // Update the detail view controllers data source
      let image = images[indexPath.row]
      detailVC.image = image

      // Set the content size for the detail view controller
      detailVC.preferredContentSize = CGSize(width: 0, height: 300)

      // Set the source rect of the previewing context
      previewingContext.sourceRect = cell.frame

      // Return the view controller for peeking
      return detailVC
    }

    /// Pop
    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        showViewController(viewControllerToCommit, sender: self)
    }
}

For peeking, the logic is almost similar to using Segues. We need to get a reference to the cell we are touching and instantiate the DetailViewController and update its data source. We also need to set a preferred content size of the DetailViewController and finally we need to set the sourceRect of the previewing context to the frame of the cell we are touching.

Popping on the other hand is very straightforward, simply show the view controller that your are peeking at.

Previewing Actions

If you now run your app and force touch on an image you should be able to get a preview of the DetailViewController.

At this stage we can also add some custom button actions to this view, for example a like or delete action. This allows a user to do some action in the DetailViewController while peeking without actually navigating to it.

Implementing these actions is also very easy. Go to your DetailViewController and add your actions, its quite similar to using a UIAlertController.

class DetailViewController: UIViewController {
    ...
}

// MARK: - UI Preview Action Items

extension DetailViewController {

      override var previewActionItems: [UIPreviewActionItem] {

          let likeAction = UIPreviewAction(title: "Like", style: .default) { (action, viewController) in
              // add some like logic
            }

          let deleteAction = UIPreviewAction(title: "Delete", style: .destructive) { (action, viewController) in
              // add some delete logic
          }

          return [likeAction, deleteAction]
      }
}

Conclusion

That is all there is to peek and pop. It is a very powerful feature that should dramatically improve the flow of an app that implements it. It allows you to use the app in such a way where you can get glances and previews of screens without having to navigate to those screens. This should make any app more productive and efficient and therefore is a feature that should be supported by all app makers.

Resources

ios peek pop 3dtouch forceTouchCapability

Author

Dominik Ringler

iOS Developer

iOS games and apps developer. I love Swift very much. /ˈɡɪf/

You may also like

A dive into the Observer Pattern in iOS applications

Often when developing iOS applications with more complex requirements we may encounter the need to react to, and perform UI updates on, not so easily accessible UI components. Another example could be that we must update an object outside our currently focused scene, perhaps created by a scene a few...

iOS
A Guide to Google Home Integrations

Within the trend of IoT, Google Home is amongst the most popular. Thankfully, Google has made the development of actions quite approachable. To get an overview of the process, let’s create a weather integration together.

Vapor