Castro blog

The latest news for podcast lovers

Back to list


Posted by Padraig on Mar 26, 2014

iOS 7 introduced the interactivePopGestureRecognizer to UINavigationController which allows users swipe from the edge of the screen to pop back in the navigation stack. This is enabled by default and requires very little consideration from developers. There is a subtle but annoying bug though that affects most of the apps I use every day. In this post I’ll explain the bug and how we addressed it in Castro.

In iOS 6 and earlier, calls to viewWillAppear: would always be followed by calls to viewDidAppear:. With the introduction of the pop gesture this is no longer the case. The user may cancel the transition, in which case viewDidAppear: won’t get called. When this happens you should revert any changes you made in viewWillAppear:.

The simplest example is with UITableViewController on iPhone. When popping back to a table view, the selected cell is deselected in viewWillAppear:. This is animated to indicate where the user previously tapped.

When the user is swiping instead of having tapped a back button it behaves differently. The default behaviour is that instead of deselecting the cell immediately, UITableViewController waits to see if the transition completes before deselecting. If the transition is cancelled the cell stays selected. I rarely see this default behaviour in production apps though.

Apple have adjusted this a couple of ways in their own apps:

  • In Music and Safari the selection is cleared immediately without any animation. There is no visual indication of the previous selection.
  • In Settings, Contacts, Messages, Notes and others the deselection animates alongside the the swipe instead of waiting for the interaction to end.

This final approach is the one we used in Castro and the one I see used most frequently in my favourite apps. It feels best because the deselection responds to your touch instead of just animating itself independently when you’re done.

To implement this, we simply deselect the cell in viewWillAppear:by calling deselectRowAtIndexPath:animated: and the animation gets pulled into the interactive transition block so that as the user swipes across the screen the cell automatically adjusts its appearance based on the percentage completed of the transition.

The caveat, overlooked by many and even by Apple (other than in Notes), is that if the user cancels the transition the cell will stay deselected and the next time they swipe back they won’t get the additional context provided by the deselection animation. The solution is to pass a block to notifyWhenInteractionEndsUsingBlock: on the view controller’s transitionCoordinator. In the block you can determine if the transition was cancelled and restore the selected state.

Our viewWillAppear: implementation is available in a gist and here’s the radar if anyone in Cupertino wants to look into it more.

Sign up to stay up to date

Get the latest news on Castro product updates and new features.