http://www.ioslearner.com/uiappearance-proxy-protocol-tutorial/
I really used to find it painstaking to customize the UI of any app according to its theme, prior to iOS 5. But with the UIAppearance Protocol introduced by Apple, things have gotten a lot better. So in this tutorial, we will be using the UIAppearance protocol.
According to Apple:
“You use the UIAppearance
protocol to get the appearance proxy for a class. You customize the appearance of instances of a class by sending appearance modification messages to the class’s appearance proxy.”
Thus we can customize appearance of instances of those classes that provide support for the UIAppearance proxy. And quite interestingly, we can also customize the appearance of instances of a class when contained in a container class, by using appearanceWhenContainedIn: method.
So, you might be wondering which classes support this. I have compiled a list of classes that support this feature, in one way or the other.
UIActivityIndicatorView:
[[UIActivityIndicatorView appearance] setColor:[UIColor orangeColor]]; |
As you can see, we set the color of our UIActivityIndicatorView as orange.
UINavigationBar:
[[UINavigationBar appearance] setTintColor:[UIColor brownColor]]; [[UINavigationBar appearanceWhenContainedIn:[MyCustomView class], nil] setTintColor:[UIColor blackColor]]; |
Here, first we set the tint color of the navigation bar as brown color. But we have another utility that comes bundled with UIAppearance, where in, we can mention what kind of appearance we want when the object is contained in a particular UIAppearance container class. We set the tint color of the navigation bar as black when it is contained inside a container (or rather a class) of type MyCustomView. We can see, that we have two navigation bars in the screenshot above, the one in the main view is of brown color, and the one that is contained in our custom view automatically has a black color.
UIBarButtonItem:
[[UIBarButtonItem appearance] setTintColor:[UIColor redColor]]; [[UIBarButtonItem appearanceWhenContainedIn:[MyCustomView class], nil] setTintColor:[UIColor magentaColor]]; |
Again, as we did for UINavigationBar, for UIBarButtonItem, we set the default tint color for all bar button items as red except in MyCustomView, where we set it as magenta. Similarly, we can also have a custom back button for our navigation bar!
UIProgressView:
[[UIProgressView appearance] setProgressTintColor:[UIColor yellowColor]]; [[UIProgressView appearance] setTrackTintColor:[UIColor greenColor]]; |
We set the tint color for the progress that has been made as yellow, and the
UISegmentedControl:
UIImage *segmentSelected = [[UIImage imageNamed:@"Segment_Selected.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 12)]; UIImage *segmentUnselected = [[UIImage imageNamed:@"Segment_Unselected.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 12)]; [[UISegmentedControl appearance] setBackgroundImage:segmentUnselected forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; [[UISegmentedControl appearance] setBackgroundImage:segmentSelected forState:UIControlStateSelected barMetrics:UIBarMetricsDefault]; [[UISegmentedControl appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor magentaColor],UITextAttributeTextColor, [UIColor clearColor], UITextAttributeTextShadowColor, [NSValue valueWithUIOffset:UIOffsetMake(0, 0)], UITextAttributeTextShadowOffset, [UIFont fontWithName:@"Courier-Oblique" size:16.0], UITextAttributeFont, nil] forState:UIControlStateNormal]; [[UISegmentedControl appearance] setDividerImage:[UIImage imageNamed:@"SegmentedControl_Divider.png"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; |
For segmented control, we give the image for the segments for both the control states i.e.UIControlStateNormal and UIControlStateSelected. We will also set the divider image. At last, we set the properties of the labels on the segments setTitleTextAttributes:. This method accepts a dictionary having the following:
UISlider:
[[UISlider appearance] setMinimumTrackImage:[UIImage imageNamed:@"Slider_Background.png"] forState:UIControlStateNormal]; [[UISlider appearance] setMaximumTrackImage:[UIImage imageNamed:@"Slider_Background.png"] forState:UIControlStateNormal]; [[UISlider appearance] setThumbImage:[UIImage imageNamed:@"Slider_Thumb.png"] forState:UIControlStateNormal]; |
For UISlider, we can set the minimum track image, maximum track image, and the thumb image. I once thought while using iBooks, on how to make a control similar to the iBooks slider, and Bingo, we get a slider exactly similar to the iBooks slider!
UISwitch:
[[UISwitch appearance] setOnTintColor:[UIColor redColor]]; |
For UISwitch, we set the tint color as red color.
UITabBar:
[[UITabBar appearance] setTintColor:[UIColor brownColor]]; [[UITabBar appearance] setSelectedImageTintColor:[UIColor greenColor]]; [self.myTabBar setSelectedItem:[self.myTabBar.items objectAtIndex:0]]; |
For tab bar, we set the tint color, and also the tint color for the selected items.
UIToolBar:
[[UIToolbar appearance] setTintColor:[UIColor blueColor]]; |
We set the tint color of our tool bar as blue color.
UISearchBar:
[[UISearchBar appearance] setImage:[UIImage imageNamed:@"Search_Icon.png"] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal]; [[UISearchBar appearance] setImage:[UIImage imageNamed:@"Search_Cross.png"] forSearchBarIcon:UISearchBarIconClear state:UIControlStateNormal]; UIImage *searchBg = [UIImage imageNamed:@"Search_Background.png"]; searchBg = [searchBg stretchableImageWithLeftCapWidth:10 topCapHeight:10]; [[UISearchBar appearance] setBackgroundImage:searchBg]; |
This is one of my favorites till now. It gives a completely new look to the search bar. Here ,we give an icon for the search bar, as well as an image for UISearchIconClear, the red circle with a cross inside it. This appears when we enter anything in the search field. We also set the background of our search bar.
Not every UI customization method in a class will respond to the appearance proxy protocol. Apple documentation clearly states:
“A class must adopt the UIAppearance
protocol to allow appearance customization using the UIAppearance
API.”
Another one is to open the class in Xcode, i.e. if we want to look at what methods are there in UISegmentedControl that support UIAppearance proxy, we can open UISegmentedControl.h fromFrameworks ->UIKit.framework -> Headers ->UISegmentedControl.h and search for the keywordUI_APPEARANCE_SELECTOR.
Moreover, one more trick is to open the class reference, and there will be some methods under a heading that mentions something about customizing appearance. For e.g., in UITabBar class reference:
As usual, you can grab the source code for the tutorial: AppearanceProxyDemo.