UIAppearance for custom properties

Creating visual consistency between all screens of an application is a goal we should set when we start designing the user interface. The UIAppearance protocol, introduced by Apple in iOS5, has the ability to propagate styling attributes UIView and UIBarButton instances.

If you’re not familiar with UIAppearance and need an overview of its features and scope, you should read my previous blog post or Apple’s documentation.

Why use UIAppearance in custom views?

Mattt Thompson compiled the list of classes and properties that can be set using the appearance proxy in iOS7, and explained how to get un updated version of this list for any iOS version.

Fortunately, we’re not limited to these properties. It is possible to define custom properties in our own classes which values can be set using the UIAppearance protocol, for the entire application or for a specific scope.

User interfaces are build using a very limited number of generic blocks: UILabel, UITextField, UITextView, UIImageView. However, instances of these base classes appear in different contexts and have different aspects depending on the context. UIAppearance allows to easily customize the aspect and adapt it to the context with very few lines of code.

UIAppearance for custom properties

Properties supported by the UIApperance protocol can only be defined in subclasses of the framework classes that conform to the protocol, typically UIView subclasses.

To declare a property in a custom class as being compatible with the UIAppearance protocol, it should be tagged with the UI_APPEARANCE_SELECTOR preprocessor macro. This simply informs users of this class that the specific property can be set through the UIAppearance proxy, which is accessed using one of the next methods on any UIView subclass:

  • -appearance: returns the proxy for all the instances of the subclass across the application
  • -appearanceWhenContainedIn: : returns the proxy for the instances of the subclass that are part of the container classes specified in the argument list

Some examples

I’ve implemented a few examples of custom properties that alter the visual aspect of some standard UI components depending on the context they are used in.

The sample application, which can be downloaded here, displays a list of photos in a table view and the large format of each photo in a detail view.

UILabel text formatting

The PhotoViewerLabel is a subclass of UILabel and defines the next custom properties which can be set using the appearance proxy:

  • contentColor: sets the text color
  • fontSize

In the setters of these properties we change the values of the superclass properties that act on the text format:

Instances of this class are used in two different contexts: as the title view of the navigation bar and as the label of each table view cell. The styling properties are set to different values in the AppDelegate -application:didFinishLaunchingWithOptions: method, depending on the context:

UIImageView with shadow

The PhotoViewerImageView is a UIImageView subclass which defines the addShadow property of type BOOL.

If this property is set to YES, a drop shadow is added to the image.

Instances of this subclass are used for the photo thumbnails displayed in each table view cell, as well as for the large format photo on the detail screen. Only the detail screen photo is set to have a drop shadow:

UITextField border style

In a similar way to the previous UIImageView subclass, the PhotoViewerCaptionTextField is a UITextField subclass which defines the photoCaptionBorder property.

The default border style for UITextField instances is UITextBorderStyleRoundedRect, but in the photo detail view I wanted the border style to be UITextBorderStyleLine:

Conclusion

Even though we have to create subclasses in order to declare properties compatible with the UIAppearance protocol, the tradeoff is beneficial. This allows us to set the property values in one place and apply them everywhere and, especially in fairly large apps with multiple screens, we can customize the appearance with very few lines of code.

 

Catalin Rosioru