UIAppearance UI全局设置

在开发中,如果想要对一些控件类,比如UIImageView、UILabel、UINavigationBar等,做一些全局的改变,通常的做法都是通过继承的方式重写该类,这样新建一个一个文件,做的多了,会感觉很麻烦。在iOS5以后,苹果提供了更简单的方式,通过UIAppearance,你可以很轻松的管理你的界面。UIAppearance提供了两个方法:

  • + (id)appearance
  • + (id)appearanceWhenContainedIn:(Class <>)ContainerClass,…

appearance使用

appearance方法使用简单,比如要定制应用中所有UIBarButtonItem的颜色,可以在UIBarButtonItem的外观代理中设置tintColor。

[[UINavigationBar appearance] setBarTintColor:[UIColor grayColor]];

或者你也可以这样写:

UINavigationBar *appearance = [UINavigationBar appearance];
[appearance setBarTintColor:[UIColor grayColor]];

appearanceWhenContainedIn使用

这个方法可以用来设置某个类在其他类里的改变。

比如我想设置UIBarButtonItem在UINavigationBar、UIPopoverController、UITabbar中的TintColor,而在其他地方则保持不变。

[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], [UIPopoverController class],[UITabBar class], nil] setTintColor:[UIColor clearColor]];

自定义类实现UIAppearance

如果想要在我们自定义的类中实现UIAppearance,需要在的类中实现UIAppearanceContainer协议,同时,在Objective-C中,还需要将相关的方法用UI_APPEARANCE_SELECTOR来标记,在Swift中,则需要在对应的属性或方法前面加上dynamic。

但实际上,UIView已经实现了UIAppearance和UIAppearanceContainer协议。因此,我们在其子类中不再需要显式地去声明实现这两个接口。

比如自定义Cell时,通过UIAppearance设置图片的圆角。

// DateCell.h
#import <UIKit/UIKit.h>
@interface DateCell : UITableViewCell
@property (nonatomic, strong) UIImageView *imageV;
@property (nonatomic, assign) CGFloat radios UI_APPEARANCE_SELECTOR;
@end

// DateCell.m
- (void)setRadios:(CGFloat)radios {
    _radios = radios;
    self.imageV.layer.cornerRadius = radios;
    self.imageV.layer.masksToBounds = YES;
}

// 在控制器的viewDidLoad方法里
[DateCell appearance].radios = 20;

注意事项

  • 使用UIAppearance设置UI效果最好采用全局的设置,在所有界面初始化前开始设置。对于在使用UIAppearance之前已经添加到界面上的控件,则没有效果。

  • 对于自定义的UI控件,使用UIAppearance无法直接改变UI控件的子控件。

    // 自定义了一个Cell,在Cell中有一个UIImageView。
    #import <UIKit/UIKit.h>
    @interface DateCell : UITableViewCell
    @property (nonatomic, strong) UIImageView *imageV;
    @end
    
    // 在控制器的viewDidLoad方法里,直接设置imageV的圆角。
    [DateCell appearance].imageV.layer.cornerRadius = 20;
    [DateCell appearance].imageV.layer.masksToBounds = YES;
    

    这种方法并不能达到预期的效果,因此我们需要给cell添加一个额外的属性,重写该属性的set方法,间接更改imageV的圆角。

    // DateCell.h
    #import <UIKit/UIKit.h>
    @interface DateCell : UITableViewCell
    @property (nonatomic, strong) UIImageView *imageV;
    @property (nonatomic, assign) CGFloat radios UI_APPEARANCE_SELECTOR;
    @end
    
    // DateCell.m
    - (void)setRadios:(CGFloat)radios {
        _radios = radios;
        self.imageV.layer.cornerRadius = radios;
        self.imageV.layer.masksToBounds = YES;
    }
    
    // 在控制器的viewDidLoad方法里
    [DateCell appearance].radios = 20;
    

参考

UIAppearance

自定义系统控件的外观:UIApearance