Two Things I Learned about Interactive View Controller Transitions

The new Interactive View Controller Transitions introduced in iOS 7 are easily one of the most exciting APIs introduced in a long time, but they've also proven to be one of the most confusing and difficult to use. Part of the problem is incomplete documentation, a lack of solid examples, and unexplained and unknown corner cases. I encountered two of these today that I want with people.

I've been struggling for a long time with an interactive transition in my fitness app, Runtime. The app uses a UIPercentDrivenInteractiveTransition to allow the user to swipe to dismiss a detail view showing a map and other information about their run. The interactive portion tracks your gesture very well. But when you lift up your finger the view then snaps abruptly into place. For several months I couldn't figure out why.

The best information I'd seen on this was the objc.io paper. But even that didn't solve my problem. Then I ran across the Apple Tech Talk lecture on Architecting Modern Apps. This video (part 1) is easily the best explanation of implementing interactive transitions that I have seen so far, and while it gave me inspiration to try again and solve the problem, it didn't provide a definitive answer.

I had a twitter conversation with my friend Elfred today and I became more or less convinced that the issue was in my implementation of the transition itself. So I started going through it and experimenting a bit to see if I could figure out what was wrong. Here's what I learned.

1) UIPercentDrivenInteractiveTransition is so amazing and convenient because it captures your UIView animation block and interpolates the animations inside of it based on the percentage of your gesture. This saves you a ton of math in practice and is actually quite helpful of Apple to include.

However, there's a pretty big and undocumented gotcha. While their implementation will look for and interpolate between any and all UIView animation blocks defined within the animated transition's -animateTransition: method, it will only interpolate between the FIRST animation block it finds when CANCELING OR FINISHING the animation! This means that if for some reason you defined two blocks, and the bulk of your animations were in the second one, then you'd notice an annoying snapping effect.

The fix for this was simple: consolidate the animations into one block (don't ask me why there were two to begin with). But you can imagine how difficult this was to figure out, since the interpolation worked as you would expect while updating the transition. It wasn't until the transition cancelled or finished that the problem occurred.

2) While the new springy UIView animation method is quite cool, and works very well with normal animated transitions, it does not support cancel or finish interpolation within a UIPercentDrivenInteractiveTransition. Again, we see the same behavior as above, where the interpolation whilst updating the transition's progress works fine with a spring animation. But when you go to cancel or finish that transition, the views will simply snap to their places. Using a normal UIView animation results in the desired behavior.

Eventually I hope to open source the transitions I'm using in Runtime. They're still a bit too specific to the app itself, but once I have them cleaned up I'll post them. Until then, I thought I'd share what I learned today in the hopes that it will help someone else struggling in the murky waters of this delightful yet confusing API.