Working with UIView’s Transition Animations

Ever since iOS 4, the iOS SDK has included UIView’s methods

and

which make it very easy to implement animated transitions between views. While very useful, they’re not without their quirks, which we’re going to break down today.

First off, while they’re two separate methods, both actually work pretty much the same way.
The main difference being is that transitionFromView:toView:duration:options:completion automatically handles the manipulation of the view hierarchy, which makes this code:

equivalent to this code:

Now with that out of the way, let’s get down to business.
Let’s say that we’re starting out with the simple single view template, that Xcode provides for us, and just put a UIView as a subview to the view of the main view controller.
Now I just want to flip that view and transition to another.

 

What? Why did it flip the whole screen? We just wanted to flip from the first view to the next one.
After a quick consultation with the documentation, it turns out that this method executes all of its animation on the superview of the two views.

Great, so let’s try this one out:

Ok, so we run this method aaaaand… hmm, no animation, we just get the purple view.
So the transition API is doing the transition, but it’s not animating. Checking the documentation reveals no answers as to why this doesn’t work. It’s a mystery!

Well, the issue here is that CoreAnimation is really lazy.
Like first Monday after the New Year lazy.
CA looks at what we give it and goes hmm, well you’re adding two views and then you want a transition to the second one all in one run loop, huh?
The easiest way for CA to do that is to disregard the whole transition thing and just put up the second view all in one pass, that way we get the end state of things.

That doesn’t work for us, though, so we have to let CA know that it should behave.
So what CA does is take everything that we give it in one turn of the run loop and bunch it up in a CATransaction, so all of our work gets done. What we want, though is to let CA finish its work on adding the subviews and animate the views after that.

There are a couple of ways to do that.

The easiest and possibly safest way is to defer the work to a subsequent turn of the runloop, by using API like dispatch_after or performSelector:withObject:afterDelay: .
In certain situations that might lead to a visible pause between showing the views and animating them, so we have to come up with something else.

CATransaction to the rescue!
At the start of every turn of the runloop a CATransaction is set up and at the end of each run loop the updates in that transaction are flushed to the screen.
So if we change our code to the following:

This makes CA run the updates that we’ve made before running our animation.

I’d advise you to use the delay method, though, since [CATransaction flush] has a big warning in the documentation:

By allowing flush to execute during the runloop your application will achieve better performance, atomic screen updates will be preserved, and transactions and animations that work from transaction to transaction will continue to function.

Keep in mind that your performance or any concurrent animations or view hierarchy modifications might get messed up, if you go with the flush method.

And with that we get our desired behavior.

Simple stuff.

6 Comments


  1. Nice work, found this really helpful. I’m trying to do the same thing in my app, but as you’ll notice in yours; regardless of the view content, uiviewanimationoptionstrantionflip transitions the views by fading them to black during transition (it’s easier to see if you increase the transition duration). Any idea how i could change that fade color? To white perhaps?

    Reply

  2. Because these are class methods , the animation blocks you create with them are not tied to a single view. Thus, you can use these methods to create a single animation that involves changes to multiple views. For example, Listing 4-1 shows the code needed to fade in one view while fading out another over a one second time period. When this code executes, the specified animations are started immediately on another thread so as to avoid blocking the current thread or your application’s main thread.

    Reply

  3. working like a charm for flipping but when i want to flip back the UI does not appears, i guess the UI has been removed from super view..
    i have UIView containing two views names as tips and option
    options flips and tips appears, but when fliping back to option it does not appears … all these views are used from storyboard … and has an IBOutlet property

    Reply

  4. I’ve been trying a custom transition with transition from view for days, and I landed on this page through some obscure stack overflow link. That one line fixed everything. Thank you so much!!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *