Tim Ross

Software Engineer - iOS, Ruby/Rails, .NET

More Fun With UIAppearance

In my last post I discussed using UIAppearance with UISS to style iOS apps. Today I discovered a few more tricks with UIAppearance.

UIKit only exposes a limited set of elements that can be styled with UIAppearance. But what if we want to style something that’s not exposed? Well, it turns out you can define your own UIAppearance proxies by appending a setter method declaration with UI_APPEARANCE_SELECTOR.

Say, for example, I want to use UIAppearance to set rounded corners on a UIView. I can create a setCornerRadius method on a UIView subclass that’s appended with UI_APPEARANCE_SELECTOR:

1
2
3
4
5
@interface MyView : UIView

- (void)setCornerRadius:(CGFloat)cornerRadius UI_APPEARANCE_SELECTOR;

@end

UIView itself doesn’t have a corderRadius property, so the implementation needs to set the value on the underlying CALayer:

1
2
3
4
5
6
7
@implementation MyView

- (void)setCornerRadius:(CGFloat)cornerRadius {
    self.layer.cornerRadius = cornerRadius;
}

@end

Now I can set the new corderRadius style on all instances of MyView with UIAppearance:

1
[[MyView appearance] setCornerRadius:3];

Or, with UISS I can use JSON to set the style:

1
2
3
4
5
{
  "MyView": {
      "cornerRadius": 3
  }
}

Now, this is pretty neat, but what if I want to expose cornerRadius on every UIView in the application, not just the subclass? Well, it turns out you can create a category on UIView that defines custom UIAppearance methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@interface UIView (Appearance)

- (void)setCornerRadius:(CGFloat)cornerRadius UI_APPEARANCE_SELECTOR;
- (void)setBorderColor:(UIColor *)borderColor UI_APPEARANCE_SELECTOR;
- (void)setBorderWidth:(CGFloat)borderWidth UI_APPEARANCE_SELECTOR;

@end

@implementation UIView (Appearance)

- (void)setCornerRadius:(CGFloat)cornerRadius {
    self.layer.cornerRadius = cornerRadius;
}

- (void)setBorderColor:(UIColor *)borderColor {
    self.layer.borderColor = borderColor.CGColor;
}

- (void)setBorderWidth:(CGFloat)borderWidth {
    self.layer.borderWidth = borderWidth;
}

@end

So now every UIView in the application can have the cornerRadius, borderColor and borderWidth elements styled:

1
2
3
4
5
6
7
{
  "UIView": {
      "cornerRadius": 3,
      "borderColor": [26, 26, 26],
      "borderWidth": 1
  }
}

Custom UIAppearance methods enable more elements to be exposed for styling. UISS makes this code more readable by allowing styles to be defined using JSON.

Comments