Essentials • iOS • 55:38
Examine tips and tricks on how to customize UIKit controls. Learn best practices on how to create assets for customizing the appearance of your app and how other apps use the appearance proxy on iOS to create an immersive user experience.
Speakers: Scott Lopatin, Jacob Xiao
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Hi, everyone. I'm Jacob Xiao, and I work on iOS Frameworks. There are more and more applications on the App Store these days, and that makes it really hard for your application to get noticed. But one great way that you can really make your application unique is to customize its appearance.
Today, I'm going to tell you about some general tips for how to get the most out of customizing your application and also some specifics on customizing different UIKit controls. We'll also have a special guest speaker at the end. But first, I'd like to show you a demo application that we'll be talking about today. It's a simple application for controlling a spaceship.
You can activate the power, which shows an animated image, and also deactivate it. And while it's activating, you can see a progress view as well. You can also open and close the doors, the front and back, And also lock them. And both of these are just UI buttons with custom images. You can also control other systems on the ship. And finally, you can view and edit the ship's logs. Including searching.
So as you can see, our application works fine, but it looks kind of plain. It has all of the standard appearances, so it doesn't really stick out. So today, I'm going to show you how to go from this standard appearance to a much more customized look. Now, those of you listening to the talk today are probably in one of two groups, either developers or designers.
If you're a developer, then the code that we talk about today will be directly usable in your applications. We'll also talk about how to prepare artwork, and that's information that you should communicate to the designers that you work with. Scott Lopatin, Jacob Xiao Now, those of you listening to the talk today are probably in one of two groups, either developers or designers. If you're a developer, then the code that we talk about today will be directly usable in your applications.
We'll also talk about how to prepare artwork, and that's information that you should communicate to the designers that you work with. All right, let's get started with some general tips for customizing your application. One of the most important parts of a custom appearance in your application is the artwork you use. Generally, for all iOS artwork, you'll want to use the ping image format. And when you use ping images, Xcode will also optimize all of your images at build time for iOS. You should also include 1X and 2X Retina versions of all of your artwork.
The 2x versions should have an @2x suffix in the file name and should be exactly double the pixel dimensions of the 1x images. Then when you use these images in your application, you can just use UIImage, image named, with a base file name, just leaving off the extension.
If your application is universal, you may have artwork that you want to be different on iPhone and iPad. And that's easy to do. Just add a ~iPhone or ~iPad suffix into your file name. And for the 2x version, notice that the tilde suffix comes after the @2x. Then, when you use the same image named method, you'll get the correct version for iPhone and iPad. Again, just leave off the extension and the tilde iPhone/iPad.
Now let's say we were creating a custom button like these. Our first thought might be to create artwork for these like this, where the entire contents of the buttons are in the artwork. But this is not the best approach to use. Instead, it's better to separate out the foreground and the background.
In this case, the foreground would be the star image or the tap text, and the background would be the green button image. Now, doing this separation allows you to reuse the same background image on many different buttons. And separating out the text from your image allows for better localization and accessibility for your applications.
Once we've separated out the image, we can use a resizable image to draw it. Resizable images are a common technique on iOS that allows you to draw a large image, like this one, with a smaller image, like this. To do so, we just separate the smaller image into regions. In this case, we would create a three-part resizable image where the left and the right are fixed and the center region resizes as necessary for the size that we're drawing at.
To create a resizable image, just use the ResizableImageWithCapInsets method. And this method allows you to pass in a cap insets, which indicate the size to remove on the left, right, or top or bottom. And you can create these cap insets with the UI EdgeInsetsMake function. This allows you to pass in all of the four dimensions that you want, and then you can use this edge insets to pass the resizable image with cap insets method to an existing UI image. And you'll get a new UI image that's resizable.
The order of these arguments is easy to remember. Just start at the top and go counterclockwise. Top, left, bottom, right. For horizontally resizable images, just pass zero for the top and bottom values. But if you use all four values, you'll get an image that's both horizontally and vertically resizable, like this one. As you can see, it's a nine-part resizable image with fixed corners and a resizable center.
Now, when you create a resizable image, there are two different ways that the center part can be resized, either by stretching or tiling. So if we use this example background image, you'll see that it has a textured appearance. So if we were to use stretching for the center part, then the center looks kind of blurry because it's just getting stretched out to the necessary width. On the other hand, if we tiled the center region, we'd get the correct textured appearance across the entire center.
When you use the resizable image with cap insets method, we'll automatically choose tiling for larger images and stretching if the center region is just one point wide. And this is because for one point wide images, stretching looks the same as tiling, and if stretching always has a better performance.
However, if you want to specify something custom for your resizable image, this is now possible in iOS 6. You can use this new method, resizable image with cap insets, resizing mode, to specify whether you want your resizable image to stretch or tile. However, note that this method is not available in iOS 6 Seed 1, but it will be in the next Seeds.
Many UIKit controls will change the size of their end caps based on the cap insets of their background images. For example, if we use this background image with these cap insets, we'd get a control with relatively small end caps. However, if we used a larger background image with corresponding larger cap insets, we'd get these larger margins. So this allows you to change the geometry of your control just by changing its background image.
Now, many images that you use in your application will have effects like shadows or glows. And when you're lining up these images with other images, you generally don't want them to line up based on these shadows. Instead, you probably want them to line up with the main edges of the control.
And in iOS 6, we have a new method that makes that easier. Image with alignment-wrecked insets. You pass this to an image to specify insets that should be used for purposes of laying out that image. And this uses the same edge insets input as resizable images that we talked about earlier.
And in fact, you can even use these two methods together to create images that are both resizable and that have alignment-wrecked insets. For this example image, we could use alignment rect insets like this. With the top inset of 0, a left inset of 1, bottom of 3, and right of 1. This image was then lay out exactly as we intended.
Now, our application includes this custom lock button. And the image for this is pretty small, which makes it kind of hard to tap. In fact, the human interface guidelines say that the minimum size of tappable elements should be 44 by 44 points. And our button is smaller than that.
But there's a technique that we can use to make its effective area larger, and that's the PointInsideWithEvent method. This is a method on UIView that gets called for all views when an event comes in to determine whether that view should get the event. The default implementation of UIView just returns whether that point is within the bounds of the view. But we can create a UIButton subclass and override this method.
In our--what we override, we'll just specify a larger region with a size of 44 by 44, and then we'll return whether the point is in this larger region. This way, if a touch comes in that's outside of the button's bounds but inside of the larger region, our button will still get the event.
However, one thing to keep in mind when using this technique is that this larger boundary is actually invisible. So it's easy to accidentally align other views to overlap this invisible region. And if you did this, you'd get unpredictable touch handling. So it's best to avoid this and make sure that all of your views have large enough margins.
As you're customizing your application, please try to use standard UIKit controls whenever possible. As you'll see today, they're very customizable. So even if you want a very custom look, you can still use default controls and customize them. You don't need to create your own new button class just to get a different look.
You also get the standard behaviors when you use the standard controls. This way, your controls will behave like all of the rest of iOS, which will make your app more predictable and easier to use for your customers. And finally, we're improving the system with every release. And so if you use standard controls, you'll get all of these improvements for free, instead of having to always work to keep your control up to date with new additions and changes.
Now, as you're customizing your controls, it's generally a good idea to customize all parts of the control. For example, with this segmented control, we wouldn't want to customize just the background image but not the divider images. Here, I've just set a custom background but left the divider images as the default blue, which doesn't look great. Instead, if we customize all of the images, we'll get a much more consistent look.
Now, if you and your application wanted to use a standard UIKit control but show it in a different orientation, like a vertical slider, this is actually something that's very easy to do today. UI view has a transform property and you can set that transform to whatever you want.
So for a vertical slider like this, we would set an affine transform that has a rotation of half pi. And this is in radians and is the equivalent of 90 degrees. If you've forgotten all of this geometry, you might need to go back to your high school geometry book to do some review.
One really easy way to get a very custom appearance in your application is with tint color. Most controls in UIKit have a tint color property that allows you to recolor them in whatever color you want. In fact, some controls even have multiple tint colors that you can set. And this allows you to heavily customize your application without having to create any custom artwork yourself. So it's a really great way to get a custom look. And we have an example of this also in the sample code.
As you're customizing your application, it can be kind of tedious to have to send methods to each individual control that you want to customize. In iOS 5, we introduced a new way that you can customize all of your controls at once. To do this, instead of sending the method to an individual control, send it to the appearance proxy that's returned by that control's class. Then, when you send the method, all of the controls of that class will be customized.
And one way that you can make it easier to do this is to cast the appearance proxy that's returned as an instance of the class that it's representing. So for the case of a slider, we would cast it as a UISlider instance. This way, we'll get build time warnings if we try to send it any methods that it doesn't respond to.
And one thing to keep in mind when using the appearance proxy is that customizations only happen for a given control when it's first added to its window. So if you already have a control that's visible and you send appearance proxy methods afterwards, the control will not get updated. Because of this, it's generally best to do all your appearance proxy customization early in your application, generally at application launch time.
And if you want to learn more about appearance proxy customization, you can watch last year's talk, Customizing the Appearance of UIKit Controls, which is available on video. You may have noticed that the silver default style status bar has been replaced in iOS 6 by this new blue status bar. In fact, some people have noticed this and have had very strong reactions.
But this is not actually just a blue static status bar. It actually matches the color of the top navigation bar that's shown. For a blue default navigation bar, we'll show a blue status bar. But if you have a tint color on your navigation bar, then we'll actually match the status bar to that navigation bar's tint color. And we'll even do this if you have a custom background image for your navigation bar or a custom subclass of navigation bar.
However, this tinting of the status bar only happens on iPhone. It doesn't happen on iPad. It also only happens when you use the status bar style UI status bar style default. For the black opaque and black transparent status bar styles, these look as they always have. Now, if your application uses one of these tinted status bars, then you should tell the system about what kind of a navigation bar you have so that at launch time, we can match the animation of your application.
And this is similar to how default.pngs work, where before your application has launched, the system doesn't know what to show, so you provide a default.png image. To provide the kind of navigation bar you have, you just need to add an entry to your Info.plist. And this entry should be called UI Status Bar Tint Parameters.
Inside of that, you'll add a dictionary with the key UINavigationBar. Then you just need to specify the style of your navigation bar, whether it's translucent, and its tint color, if it has one. Once you've got this set up in your Info.plist, the system will match the status bar style at launch time.
Another appearance change in iOS 6 is that we now show shadows beneath the navigation bars, toolbars, and tab bars. This is a pretty subtle effect, so I've kind of increased the contrast here so you can better see it. Now, this effect happens in your application automatically. There's nothing that you need to do to opt into it. However, there are a few things to keep in mind about these new shadows.
For this navigation bar, here are its bounds, and here is where the shadow appears. As you can see, the shadow actually extends beyond the bounds of the navigation bar and into the area of the content below. And this means that if your content view is above the navigation bar in its hierarchy, the content will actually cover up the shadow, making it invisible. So always make sure that your bars are on top of their content area so that their shadow is visible.
If you still notice that your navigation bar's shadow is invisible, then check that its ClipSubviews property is turned off. If ClipSubviews is turned on, then the shadow will be clipped to the navigation bar's bounds, which again will make it invisible. If you create your navigation bar in Interface Builder, then you can change the ClipSubviews property here in the Attributes Inspector.
If you use custom navigation bar subclasses or toolbar subclasses, then we have an easy way that will make it easier for your application to use these with UI Navigation Controller. The new method, initWithNavigationBarClass, ToolbarClass, allows you to create a navigation controller that has your custom subclasses already ready to use. This is new in iOS 6, but the great thing is it's available back to iOS 5. So if you use the iOS 6 SDK, you can still use this even if your deployment target goes back to 5.0.
Now let's talk about customizing some specific UIKit controls. We'll start with buttons. Buttons are pretty easy to customize. First, you should remember what we talked about earlier, to separate out the foreground and the background. And also, we should use resizable images for the background whenever possible. Using resizable images makes it so that your images are smaller and also allows you to reuse them in different buttons, even if those buttons have different sizes. For the background, we can use the setBackgroundImageForState method to set the background image. And for the foreground, we can either use setImageForState or setTitleForState. And again, setting the title as text instead of an image is better for localization and accessibility in your application.
Now, these methods introduce the new state per input, and this allows you to customize the control differently for its different states. The possible values you can use here are Normal for the default state of control, Highlighted for while the button is being tapped, disabled for when the control can't be used, and selected for toggleable or selectable elements, like UI Segmented Control. These are the custom images that we're using for our custom button in the example code.
And when you're setting your own custom images for your controls, it's always good to at least set the normal state's value. If you only set the normal state and don't set any of the other states, then we'll use the normal state's value and modify that for the different states as necessary. Also, these control states are not actually mutually exclusive. So, for example, you could set a different image for while a control is both highlighted and selected. And to do this, just use bitwise or to combine the states together.
Segmented controls are very similar to buttons, but they can have multiple sections. Here is the custom segmented control that we use in the example application. And here are the components that make it up. Once again, there's a background image that we'll use a resizable image for so that it can stretch to whatever size is necessary. And for segmented controls, if you don't use an image that's already resizable, then we'll make it resizable for you by assuming a center region of one point and using the rest as left and right end caps.
Also, for segmented controls, it's generally a good idea to set at least the normal and selected values for the background image so that the currently selected segment will look different visually from all of the others. There's also a divider image that's shown in the middle between two different segments.
And we can set custom images for that as well. And notice that the custom image method for this allows us to set different images for different left and right states. And these are for the states of the two segments on the left and right of a given divider.
Steppers are a control that we introduced in iOS 5. And in iOS 6, we're adding a lot of customization options to them as well. Here are the components of our custom stepper. In the foreground, there's a decrement and increment image that we can set. And in the background, there's a divider image and a background image that are customized very similarly to segmented controls.
Sliders are very simple, easy to use controls, but they also have a lot of available customizability. For example, here is a default slider. And here's the custom slider that we used in our application. As you can see, it's very different, and here are the elements that make up those changes.
On the left and right sides of the slider, there's a minimum and maximum value image. The images that you use here should represent the property that the slider is changing. In the case of our application, this slider controls the speed of the spaceship. So we're using images that represent the spaceship going slow and fast.
There's also a thumb image that goes in the center of the slider, and that can be customized as well. Finally, there are track images that are shown at the back of the slider, and these can be customized for the minimum on the left and the maximum on the right. Once again, you should use resizable images for these since they'll be shown at different widths depending on the value of the slider.
Progress views show the status of an ongoing operation in your application. Here is a custom slider view that we used in the example application and here are its components. There's a track image at the back and a progress image in the front. The track image is drawn across the entire width of the progress view, whereas the progress image is drawn just in the section that's completed and is put on top of the track image.
Note that this is a different behavior than sliders, where for sliders only half is drawn in each different custom image. Once again, with progress views, it's good to use resizable images so that your image can be redrawn to whatever width is necessary for the current state of the progress view.
Switches are a very basic control in UIKit, but even they have a lot of customizability available. In iOS 5, we introduced the On Tint Color property, and this allows you to set the color of the on part of the switch. In iOS 6, we're adding even more options.
You can now set a Thumb Tint Color, which affects just the color of the center thumb, and you can set a Tint Color, which affects both the thumb's color and the color of the off part of the switch. And of course, you can combine all of these colors however you want to create exactly the appearance that you want.
We're also adding methods to set custom images for your switch. This lets you set a custom image for the on and off part of the switch. But it's a good idea to keep these images at 77 by 27 points or smaller so that they fit within the switch.
Next, let's talk about customizing the navigation bar for our application. Navigation bars are a common element in many iOS applications, and there's a lot that we can do to customize them. We'll start with the background image. Once again, notice that the background image is separate from the text and all of the buttons. Again, this allows for better reusability and better localization and accessibility.
Also, instead of drawing the entire background image, we'll use a smaller, resizable image, as usual. Once we have this smaller image, we can use the setBackgroundImage for bar metrics method to set this for the navigation bar. Notice that there's a new parameter here for bar metrics. Bar metrics specify the different types of bar heights. For example, the default is shown in portrait on iPhone, and this has a height of 44 points.
On landscape on iPhone, we decrease the height of the navigation bars to 32 points, and this is represented by the landscape phone bar metrics. And as its name implies, this doesn't happen on iPad. On iPad, all navigation bars have a height of 44 points. Amen. So using bar metrics, we can set different custom background images for each of these different bar metrics.
When you're setting your image, if you use an image that's taller than the height of the bar, which is 44 in default and 32 in landscape, then we won't clip it to the height of the bar, but we'll actually show the full height of the image you set.
And this allows you to set a larger image that will extend into the content below, so you can provide your own shadow as part of the custom background image. And if you do this, then we'll turn off the new shadows that we add in iOS 6 so that they don't interfere with the shadow that you're providing in the background image.
And speaking of shadows, we can also customize the new shadows that were added in iOS 6. To do so, just use NavigationBar's setShadowImage method, and you can set the image that you want to use. This is the custom image that we used in our sample application. You can't see it there? It's right here.
It's very small because this should be a very subtle effect. The shadow is generally just a very -- a few points tall, and we can use a one-point wide image because since it's the same across the entire width of the navigation bar, we don't need to provide the entire width. We can just use a one-point wide image, and it'll be tiled or stretched.
Now that we've customized the background, the default text that's shown there doesn't really match very well. But we can customize the appearance of that text as well. To do so, we can just set a dictionary for the bar's title text attributes. Title text attributes allows us to set custom fonts, colors, and shadows for the text that's shown in the navigation bar. And this technique is used in many other UIKit controls as well to set a dictionary of text attributes to customize the text that's shown.
So we've now customized the navigation bar's background image, its shadow image, and its title. The only parts remaining are the two buttons that are shown. And these are represented by UI bar button items. will start customizing the bar button item with its background. And as usual, we'll use a resizable image for the background. If you don't use a resizable image for your bar button item's background, then we'll make it resizable for you once again by using -- assuming a center region of one point and the rest as left and right end caps.
Just like with the background of the navigation bar itself, we'll use a different image for the background in landscape. Now, the images you use for the background images for bar button items should generally be 30 points tall for the default bar metrics and 24 points tall for the landscape bar metrics. Once you have your images, you can set them with the method setBackgroundImage for state bar metrics. And this is how we can set these two background images for our bar button items.
If your bars include done style buttons in addition to bordered style buttons, then you may want to set different background images for the two types of buttons so that they look visually different. In iOS 5, you could do that by setting manually a different background image on each of these two types of buttons. But if you use the appearance proxy to customize all of the background images for your bar button items, then the same background image would be used for the bordered style and done style buttons. In iOS 6, we're introducing a method to make this easier.
This new method allows you to set a background image and specify a style so that you can have different background images for the bordered and done button items, even if you use the appearance proxy. Next, we'll customize the back button. Once again, this is just a UI bar button item, and we can customize this by using the different method setBackButtonBackgroundImage. Again, we'll use a resizable image, and this time we'll use asymmetric cap insets for the asymmetric image that we have.
Now, when you have all of your images, depending on your design, you may want to customize the positioning of the different elements that are shown in your navigation bar. And there's lots of properties that you can use to do that. For the text's position, you can use these three properties to set the positioning of the back button items text, the main title text, and the text for normal bar button items. If you want to change the positioning of the backgrounds for the different bar button items, you can use these two properties. And finally, if you have images for your bar button items, then you can also customize their positions using the image insets property.
Now, toolbars are customized very similarly to navigation bars. Once again, we can set a custom background image and a custom shadow image. And these follow all of the same rules as their equivalents for navigation bars. The only difference is that for toolbars, the shadow will extend up into the content instead of down into the content as with navigation bars.
Toolbars also use the same UI bar button items as navigation bars, and these can be customized in the same way that we talked about earlier. However, for toolbars, you can also use plain style bar button items. These are using the UI bar button item style plain type, and they look like this. And if you want to use a custom image for your plain style bar button item, all you have to do is create a simple monochrome image like this one.
These images are drawn as a stencil and the colors in the image are actually ignored. So, for example, for this image, the black will be ignored and the image will be colored as white. And then the shadow etched effect that you can see in the toolbar when the image is used will be applied for you by the toolbar. So you don't need to include this in your artwork. You can also use the tint color of both the toolbar and the bar button item to change the colorization that happens for your custom image.
Now, search bars always include a search field at the top and can optionally include a search bar beneath that. And search bars can be heavily customized as well. If we separate out the components, you can better see which parts can be customized. You can set a custom background image that's shown behind. Also, a custom background image for the search field itself, which is drawn on top of the entire search bar background.
And finally, you can customize the different icons that are shown within the search field, like this magnifying glass icon. Now, the cancel button itself does not have a direct way to customize it, but it's represented by a UI bar button item. And this means that you can use UI bar button item appearance proxy customization to customize it just like other UI bar button items.
If you have a scope bar in your search bar, then you can also customize that. There's a different background image for the scope bar, and the scope bar also has a background image and divider images that can be customized in the same way as segmented controls. This is what our customized search bar looks like when you put the pieces back together.
Tab bars are a very complex control that have a lot of different parts. Here's a standard tab bar and here are its components. As you can see, you can customize the tab bar both with the UI tab bar itself and with the UI tab bar items that appear inside of the tab bar.
On the tab bar, there's a background image and a shadow image that behave in the same way as the other bars that we've talked about. And there's also a selection indicator image. This image is drawn in front of the background of the tab bar and behind the currently selected tab. In the tab bar Items, there's an image and title that represent the item, and there's also title text attributes that you can use to change how the title is drawn.
Here are the custom images that we use in our sample apps custom tab bar. As you can see, we've customized all of the images for the tab bar, and we're also using different custom images for the tab bar's items. Also, you may notice that none of the images, the custom images that we used, include any of the text. And also, each of these images is separate from each other. We're not mixing them together. When we put these back together, this is the final tab bar that we get.
Now, whenever you create a tab bar item, it should have an image that represents it. These images should be just simple monochrome stencil images, just like the plain style toolbar items that we talked about earlier. And this plain stencil image will be drawn as gray when the tab bar item is unselected and will be shown with a glowing blue when the tab bar item is selected. Again, you can use the tab bar's tint color or selected image tint color to change the colorization that occurs.
But if you don't like this default appearance and don't want to use it in your application, you can also set fully custom images that are used as is in the tab bar without any effects applied to them. That's what we did in our custom tab bar in the application, and these are the images that we used. Notice that the unselected images have an inner shadow, and the selected images have a metallic gradient that's different from the standard blue glowing look.
To set these kinds of images, you can use Set the Finished Images for the tab bar item. The word "finished" here means that these images should have all effects already included in them. We won't add any colorization or shadows or glows to them, so you should include any effects that you want inside of your custom artwork. Also, notice that you have to set both the selected and unselected images when you're using this method. And this is to make sure that the two images will match each other. Once you've set these, the images you set will be used directly in the tab bar.
Table views are a very complex topic and we could probably spend an entire session just talking about how to customize them. So we'll just talk about a few different small topics today. If you're customizing a group style table view, then you may want to change its background image from the default background so that it better matches the content that you show.
To do so, you can use the setBackgroundView method on TableView. This allows you to set any kind of UI view you want as the background that will be shown behind the TableView. In the sample application, we've just used a basic image view with a tiled image as its contents.
Another common item to customize is the headers that are shown in table views. And in iOS 6, we're introducing a new class to make that easier. The UI table view header footer view is the class that we use for the default headers that are shown in table views. And with this class, you can now -- it makes it easier to do small changes to the headers. So, for example, in the sample application, we use the standard headers, but we just slightly change its text color to better match the rest of our content.
And finally, remember that tables include cells and headers that are just views, so you can always add whatever custom controls or views you want to them to do any customization you want of your table view. All right, now that we've customized all of the different parts, let's see how it looks like when it's all put together in the sample application.
As you can see, our application now has a fully metallic theme to it. It has a custom navigation bar, including the bar button item, and it also has a new status bar color that matches the navigation bar. We also have our fully customized tab bar, including a different appearance for both the selected and unselected tabs. We also now have our custom button, including all of the different states. And we have our custom progress view.
We can also see the customized segmented control that matches the navigation bar. And for the lock button, if I click just a little bit outside of its bounds, you can see that it's still toggled because we're using the technique point inside with event that I talked about earlier.
Also, all of the controls and the background image that's shown behind them are now customized here. And finally, in the Logs view, we have a customized toolbar and our fully customized search bar. And this sample application is actually available for you to download from the WWDC website. Just go to the webpage for this talk and you can download it.
So that's great, but how does all of this actually work in a real shipping application? Well, we have Scott Lopatin from Find My Friends here to talk about how they used customization to customize their app's appearance. Scott? Thank you, Jacob. You'll never believe it, but Find My Friends uses a ton of appearance customization.
Today I'm going to give you an overview, a quick overview of the Find My Friends skin look, how we used code organization to put all of our skinning code into one place, and then I'm going to cover some specific UI elements and how we skin those. If you haven't seen on Monday on the developer site, we actually released beta 2 of Find My Friends, which includes some great new features. One is this new friends tab, which includes a split map and friend list on the main screen.
An easy way to find your nearby friends. And an industry-first feature which lets you set geofences on yourself or friends which fire notifications that push to the other person. As you can see, Find My Friends includes this custom leather texture, which looks great on a retina display and especially the new iPad, providing an amazing immersive experience. Let's take a look at that.
Now, I know what you're probably thinking. There's kind of some debate out there as to whether this is actually a cool design or if it's merely kind of a -- somewhat of a skewed distraction. But in any case, The application, once you skin it and provide a custom theme, lets it easily stand out amongst the many different applications out there on the App Store. And that's probably why you came to this talk.
The UI isn't exactly lickable, but it's kind of alive. So when we set up to make Find My Friends, we wanted every single background, texture, button, selected state, unselected state, everything completely custom. This is a ton of images, especially when you consider buttons have control states and you have 1X and 2X images. So how are we going to organize all this custom theming code in our application? Well, we're going to do it with a theme.
This theme lets us organize our code into a certain place, and I'm going to show you how to do that in our next part of the talk with code organization tips. Our theme all started with a protocol. Think of this protocol as a catalog. of all the different colors, images, and fonts used throughout your application.
Notice we didn't refer to the colors as like the red color or the blue color, but merely as their usage within the application. You'll also note that to get an immersive theme, you don't have to pick 20 different colors. Just a few basic colors that kind of go together will get you very far.
Now that we've defined this theme protocol, we can implement it in many different ways. The sample application uses the same method, and that's how Jacob switched between the two themes with just one line of code. So now we're providing a leather theme, but you can implement any other different kind of theme you want based on user selection or A/B testing when you're developing your application to show off different aspects that you might be playing with on the side. This theme class can also do some work to return the current theme, let's say, and then anywhere in your code you can just say theme, current theme, get me those images or colors, fonts, whatever, used throughout your application.
Now, we have a ton of custom buttons used throughout the application, and we could have made subclasses for all these, but instead we did something a little bit different. First... We made an enumeration of all our button types. An add button, a refresh button, any different types. And then we use these types when we're making our new buttons. So anywhere in our code, here we're creating a new button. And immediately we're saying theme button with type from our current theme.
In our theme class, we're defining this method, themeButtonWithType. And then we can check in this method, okay, here is the leather button types. Let's pull out from the theme our current background image and set this for the button. A little trick we used also is to add the state into this theme button method. So if we do button image for state, we have one method to get all of the images for this button and that method will pick out from which state to return the proper image. That's reducing the number of methods on our theme file.
You'll probably notice that a lot of your buttons have probably the same different styles, maybe the same font color, the same shadow. So set all these first and then override at probably the bottom where these differ. And you'll probably find that these are pretty small differences. Sleep better at night knowing that the right images are going to the right control state by this trick of naming the images after the control state used in your button. Saves a lot of hair loss.
So to overview, our theme class defines this protocol, this list of all our images, fonts, and colors. We have enumerations of styles of each type of object, buttons or different objects. and the main theming methods, this one line of code we can add after creating any of our objects anywhere in the code to theme. Then the concrete implementations of that protocol can just know how to do the work of finding those images, fonts, and colors.
At the end of the day, You have this one line of code that wherever you are in your application, whenever you're creating a new button or a new object, you can say, yeah, just theme this, and the theme files will do all the work. Another huge benefit is when you're working with designers, you have one place to go to say, oh, yes, I am using the right color or the right shadow offset or the right shadow color.
Now I'm going to talk about some specific examples of how we skin some of our UI elements in Find My Friends. I'm going to talk about the navigation bar. Our new tab bar in 2.0. Sand stitching, you'll notice. And the segmented controls. Starting with the navigation bar, when we make a navigation controller, we're pulling out the navigation bar and calling that one line of code to theme, theme nav bar with style. Then we can go through and do the work such as pulling out a background image from our current theme, whatever that current theme is that the theme class manages, and setting that set background image for bar metrics.
For our bar button items, we're using appearance when contained in UI Navigation Controller. And that's because our toolbars also have bar button items, but they might have a different kind of custom style, which we don't want to overlap with the navigation bars. Since our navigation bars have the same background image in this case, we're using appearance when contained in UI Navigation Controller. And this is defined in the theme method where we're theming the navigation bar. Even though we're theming the navigation bar, we can also apply these appearance proxies for everything related to those navigation bars.
Our background images are nine-part images with UI Edge insets. If these edge insets differ depending on your theme, you can always have the theme also return edge insets if you'd like. And then we define the image with resizable image with cap insets. Little trick we used is this custom leather texture navigation bar background has a texture.
So you can use the alpha channel of the background images for the bar button items to let the texture shine through so you don't have any problems matching up textures or wasting bits in your application of extra texture. Finally, styling text with the text -- title text attributes that Jacob mentioned. A dictionary containing the font, text color, shadow color, and shadow offset used in the bar button items. Again, we're using the appearance proxy, appearance when contained in in this case as well.
So what we're left with is this main one line of code where we create a navigation controller and say theme nav bar. And all the aspects of this navigation bar are themed with one line of code from wherever we are in our application. Moving on to tab bars, done similarly with a set background image. We'll probably create a theme tab bar in our theme class and we do some work like setting the background image.
We use finished images for our tab bar, so for the items when we create them, we're setting finished selected and finished unselected images. And you'll notice we're actually using the same method in our theme class to pull out those images, just set it in Boolean whether they're finished or not, providing -- so then you can look in one place to see what images are actually being returned in this case.
Our selection indicator image set on the tab bar is somewhat translucent as well, providing that texture to shine through even when an item is selected. And you'll notice I didn't mention the text, and that's because when your tab bar items are created, pull out a localized string from your localized strings file and set init with title with that localized string.
To style that text, use our familiar title text attributes to set the font, text color, shadow color, and shadow offset. In this case, we used the main appearance proxy, not when contained in, because we have one tab bar in our application. And even if we had more, they'd probably look the same, so we're just going to set it for all the tab bar items used.
Finally, segmented controls. We have a few different types of segmented controls in the application. There's a bunch of different parts, but really it boils down to three API calls: setBackgroundImage, setDividerImage, and setTitleTextAttributes. For background image, we have one method defined in our theme where we pass through the control state and set these for the normal, selected, highlighted, and disabled states on our segment.
These are, again, nine-part images using UI Edge insets. The segmented control knows, depending on the position of the button or the background image in the segment, where to slice off the edges to stretch and make the proper size button. So in this case, the selected is on the left and it's chopped off the right side of the UI Edge inset.
For divider images, as Jacob mentioned, you can have different divider images depending on if the left is selected or if the right is selected. And you can pull out different images for all of these. In our case, though, we have the same image no matter if the left is selected or the right is selected, so we just do one call with one image for the normal state, and all the other states are picked up as this is the lowest level. Finally, those familiar title text attributes to style the text on the segment not drawn as background images into the segment to control. Setting the font, text color, shadow color, and shadow offset.
So today I went through an overview of the Find My Friends skin look, getting far with an immersive experience and not using tons of different colors, showed you some code organization tips of how you can organize your code with a theming protocol. The sample code provided with the session uses this as we've done. And then I covered some specific UI elements and how we skin those in Find My Friends. Back to Jacob.
Thanks, Scott. So today we saw some general tips when customizing your application, including some of the new appearance changes in iOS 6 and how to use resizable images to make your images smaller and more reusable. We saw some specific details about customizing different UIKit controls, including how to prepare your artwork and how to separate the different elements inside of a control to best customize it. And finally, we heard from Scott about how Find My Friends customized their appearance, including how they achieved their skin look and also how you can use themes to organize and maintain your custom artwork and your customizations.