Auto Layout and Core Animation

Auto Layout was introduced by Apple in OS X 10.7 Lion and now, it has been available since iOS 6. Auto Layout is really an interesting and useful technology: it solves one of the most important issues layout the user interface to screen size changes. These changes can be either due to screen orientation changes (landscape to portrait and vice versa) or due to new screen size (iPhone 5).

Before Auto Layout, you had to code the layout for each UI element and interface orientation. Additionally, if there were variations of the content size (for example, change of the text length in the button title, because of the text localization or different height of the tableview cells because of the different text content, and so on), you had again to manage that by yourself adding a lot of extra code just to make things look right.

Auto Layout fixes all these problems for you: it automatically adjusts the layout of the UI elements according to some simple rules you provide.

Now, there are already different tutorials about Auto Layout in the Internet and I don’t want to provide here a new one. For an in-depth explanation of Auto Layout attend one of our intensive iOS training classes or check the WWDC12 videos.

Instead, what I want to show you here is how to combine correctly Auto Layout and Core Animation. In fact, if you already tried to use both, you noticed that it is really hard to animate a view and keep the constraints you fixed in Interface Builder or programmatically. This is especially true, if you are trying to animate the view frame.

Let’s give a look at this particular problem. Launch Xcode and create a Single View Application. Name it LayoutMagic. Open the ViewController.xib file. Make sure Auto Layout is active (it should be already active by default): the Use Autolayout flag should be selected (Fig.1).

Figure 1

Then, add a navigation bar to view top as shown here:

Figure 2

Make sure the navigation bar has the same constraints shown in the following picture:

Figure 3

Here, you can see that the navigation bar is constrained to the top, the leading and trailing space to its superview. This means if the superview layout changes, the navigation bar will be constrained to the top of the view.

Let’s see what happens if you animate the navigation bar frame in the usual way. Let’s add a tap gesture recognizer to the main view, so that every time you tap onto this view, the navigation bar moves out of or into the screen with a smooth animation. Obviously, we need an outlet to the navigation bar. So, I create its property in the ViewController.h file:

and connect it to the navigation bar in Interface Builder. Now, go to the viewController.m file and add the following instance variable:

We need this boolean to check if the navigation bar is on the screen. In the viewDidLoad, add the following lines of code:

As you know, the handleTapFrom: method will be fired every time you tap on the view. Now, if we had no Auto Layout, we could simply write the implementation of this method in this way (maybe in a more elegant way than here, but this is enough for this example):

As you can see, I check if the navbar is visible. Depending on that, I animate the navigation bar frame in or out of the screen.

Now, if you try it, the animation works perfectly here. But… try to change the orientation of the device to landscape and tap on the main view a couple of times (Fig. 4). Wrong, right? This is not what you really want.

Figure 4

This happens because the above source code is forcing the frame of the navigation bar to the size of the view in portrait and the Auto Layout constraints added in Interface Builder get broken. We could fix this detecting the UI orientation and adding some lines of code to adjust the UI layout depending if the UI orientation. But, you don’t want to do that again.

Auto Layout to the rescue!

So, let’s see how to fix the wrong layout of the previous picture using Auto Layout. In Auto Layout, each constraint is a UIKit object of type NSLayoutConstraint. Very important, this object is animatable. You know that a constraint is represented by the following linear equation:

In the particular case of our navigation bar, the top constraint (between the top edge of the navigation bar and the top edge of the superview) can be expressed in this way:

where in our initial conditions multiplier = 1.0 and constant = 0.0. Then, the previous equation becomes

Now, we want to animate the navigation bar, so that

This means we want to move the top edge of the navigation bar 44 points away from the top edge of the main view.

Let’s translate everything in code, but first, we need an outlet to the constraint we want to animate. So, select the Vertical Space - Navigation Bar - View constraint and create this outlet:

Connect this property to the constraint in Interface Builder. Now, the previous handleTapFrom: method becomes:

Here, the important steps are:

  1. You fix the final value of the constraints. In this case, we want to change the constant of the topConstraint property to -44.0.
  2. Finally, within the animation block, you force the layout of the navigation bar

Build and run it. Check the portrait and landscape orientation. Everything works fine.
You can download the example from here.

Keep coding.




(Visited 178 times, 1 visits today)