A common user interface paradigm in TripGo is to provide a list view with an associated map view. On the iPhone we display them on top of each other, while on the iPad we display them next to each other, which we have achieved by using separate storyboards for both devices. However, maintaining two storyboards has a number of downside and with iOS 9 around the corner, that adds the ability to show apps side-by-side, it is time to kiss goodbye to this approach. After briefly investigating the now more powerful
UISplitViewController, we are now saying “Hello” to the magic world of trait collections, custom transitions and container views!
The basic structure that we follow is that we have a navigation controller onto which we push custom container view controllers, which have a child view controller for managing the list view, and additionally a map view which is managed by a custom class. The tricky/fun part is creating a nice transition on the iPad when pushing one of these views on another: the map should stay in place and only gets its content updated, while the list view gets the appearance of being pushed.
Without custom transition
With custom transition
Using a custom transition is much less jarring since it doesn’t use a full-screen push and the map does not need to rebuild either, which speeds up the app and allows a smoother flow.
The key to achieving this is by creating a class that conforms to
UIViewControllerAnimatedTransitioning and by then handcrafting how the views transitions from one view controller to the next.
This needs quite some care and my progress today ground to a halt, when I hit the following error message:
Terminating app due to uncaught exception
UIViewControllerHierarchyInconsistency, reason: ‘child view controller:
<MyContentViewController: 0x7fba23a822a0>should have parent view controller:
<UINavigationController: 0x7fba19016600>but actual parent is:
What caused this was that during the transition, the child view controller’s view was temporarily put onto the transitioning context’s container view. However, this is a no-no since the transitioning context’s container view belongs to the view hierachy of the navigation controller. This means that inserting my child controller’s view as a subview to that, even temporarily, violates the child-parent relationship that was set up before, resulting in this crash.
My hope is that this is helpful to anyone hitting the similar error. My advice is: rethink the internals of the transition and to make sure that the child-parent hierarchy is maintained at all times.