As a bewildered Dorothy says in the movie The Wizard of Oz, “I don’t think we’re in Kansas anymore.” When you open your iOS 6 project in Xcode 5 and run it in the iOS 7 simulator, you’ll know instantly that things have changed:
Gone is the colored status bar background; the status bar is always transparent, and all apps are full-screen apps, underlapping the status bar. A button has no rounded rect bezel, unless you draw it yourself as the button’s background. Many interface objects are drawn differently, with different dimensions. The subtle bar gradient is gone; colors are flat, unless you draw a gradient background yourself.
Actually, you’ll be lucky if your app launches at all! If you were setting
tintColor on an
appearance proxy, you’ll get a compile error, or your app may even crash. Tint color is now inherited down through the view hierarchy: set it in the storyboard, or on your window, to get a uniform color theme for interface objects.
To be honest, the pair of screenshots above conceals the Awful Truth. My app didn’t look like the second screenshot until after I tweaked it for several days. When your app first runs under iOS 7, it will probably look terrible, with incorrect bar colors and a partially obscured interface, as in this pair of screenshots:
The bar color problem is because bar styles have changed. By default, a bar wants to be off-white and translucent. That leads to the second problem: all apps are full-screen apps, so your interface underlaps the status bar — and any translucent bars as well!
The solution has to do, ultimately, with view controllers. A view controller’s view has always been resized as it is placed into the interface, including a navigation or tab bar interface; but now it’s being resized differently. Once you understand the new resizing rules, you can prepare for them.
If the interface has no top bar, allow for the new 20 pixels of underlap behind the status bar. With autolayout, the new UIViewController
topLayoutGuide property will help; it moves dynamically to the bottom of the status bar or top bar, so pin the top of your interface to it. Alternatively, hide the status bar; that’s done in a new way too, by implementing
prefersStatusBarHidden in your view controller. To prevent your interface from underlapping a bar, set the bar’s
translucent to NO. Alternatively, set your view controller’s
I opted to hide the status bar and explicitly set the tab bar’s
UIBarStyleBlack with a
translucent of NO. Now my view is completely visible! Additionally, I stopped setting the
finishedSelectedImage of my tab bar items; a bar’s
tintColor is now the color it tints the bar item images (and to set a bar’s background tint, you now set its
barTintColor). I also changed the tab bar’s text style; I made the progress view black; and I brightened up the background. Here’s the result:
If your view contains a standalone top bar, such as a UIToolbar on the iPad, you’ll want it resized to underlap the status bar without obscuring its contents. To arrange that, give the bar a delegate and implement
positionForBar: to return
Making your app both iOS 6-native and iOS 7-native, with the interface correct on both, can be daunting. Use autolayout if you can; in the storyboard, pin your interface to the Top Layout Guide and the Bottom Layout Guide, which (incredibly) are backwards-compatible. If you can’t use autolayout, use the new Interface Builder iOS 6/7 Deltas to compensate for the 20 pixels of the status bar, and set your view controller’s
edgesForExtendedLayout using conditional code. (My own approach? Abandon iOS 6 support altogether.)
Making your interface look good, after iOS 7 comes along and spoils it, is exasperating. But it’s worth it! Afterwards, you’ll be ready for fun, adopting some of iOS 7′s great new features, such as UIKit Dynamics and custom view controller transition animations.
Bonus tip: Be sure to switch your Deployment Target to iOS 7 and recompile to discover the vast number of deprecations. Many have to do with text drawing with CGContext or NSString, along with the UITextAttribute constants; iOS 7 has acquired OS X’s TextKit, so attributed strings are now truly first-class citizens.