今天想聊的是UIKit: UIAppearance
UIAppearance是什么?
UIAppearance实际上是一个协议,我们可以用它来获取一个类的外观代理(appearance proxy)。为什么说是一个类,而不明确说是一个视图或控件呢?这是因为有些非视图对象(如UIBarButtonItem)也可以实现这个协议,来定义其所包含的视图对象的外观。我们可以给这个类的外观代理发送一个修改消息,来自定义一个类的实例的外观。
我们以系统定义的控件UIButton为例,根据我们的使用方式,可以通过UIAppearance修改整个应用程序中所有UIButton的外观,也可以修改某一特定容器类中所有UIButton的外观(如UIBarButtonItem)。不过需要注意的是,这种修改只会影响到那些执行UIAppearance操作之后添加到我们的视图层级架构中的视图或控件,而不会影响到修改之前就已经添加的对象。因此,如果要修改特定的视图,先确保该视图在使用UIAppearance后才通过addSubview添加到视图层级架构中。
其实,UIAppearance是诞生在在iOS 5之后。在iOS 5以前,我们想去自定义系统控件的外观是一件麻烦的事。如果想统一地改变系统控件的外观,我们可能会想各种办法,如去继承现有的控件类,并在子类中修改,或者甚至于动用method swizzling这样高大上的方法。
幸好的是,在iOS 5之后,出现了两个Protocol,分别是UIAppearance 以及UIAppearanceContainer,通过这两个协议,我们可以在开发过程中规范对于UI的定制工作。
下面我们来了解下如何使用的
UIAppearance的使用
UIAppearance Protocol主要使用以下两个方法:
/* To customize the appearance of all instances of a class, send the relevant appearance modification messages to the appearance proxy for the class. For example, to modify the bar tint color for all UINavigationBar instances:
[[UINavigationBar appearance] setBarTintColor:myColor];
Note for iOS7: On iOS7 the tintColor property has moved to UIView, and now has special inherited behavior described in UIView.h.
This inherited behavior can conflict with the appearance proxy, and therefore tintColor is now disallowed with the appearance proxy.
*/
+ (instancetype)appearance;
/* To customize the appearances for instances of a class contained within an instance of a container class, or instances in a hierarchy, use +appearanceWhenContainedInInstancesOfClasses: for the appropriate appearance proxy. For example:
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[UISplitViewController class]]] setBarTintColor:myColor];
[[UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[[UITabBarController class], [UISplitViewController class]]] setBarTintColor:myTabbedNavBarColor];
In any given view hierarchy the outermost appearance proxy wins. Specificity (depth of the chain) is the tie-breaker.
In other words, the containment statement is treated as a partial ordering. Given a concrete ordering (actual subview hierarchy), we select the partial ordering that is the first unique match when reading the actual hierarchy from the window down.
*/
+ (instancetype)appearanceWhenContainedIn:(nullable Class <UIAppearanceContainer>)ContainerClass, ... NS_REQUIRES_NIL_TERMINATION NS_DEPRECATED_IOS(5_0, 9_0, "Use +appearanceWhenContainedInInstancesOfClasses: instead") __TVOS_PROHIBITED;
+ (instancetype)appearanceWhenContainedInInstancesOfClasses:(NSArray<Class <UIAppearanceContainer>> *)containerTypes NS_AVAILABLE_IOS(9_0);
这两个方法就不多加详细阐述了。全局修改使用appearance
,修改指定的使用appearanceWhenContainedInInstancesOfClasses
举个例子:
[[UINavigationBar appearance] setBarTintColor:myNavBarBackgroundColor]; // 全局修改
[[UIBarButtonItem appearanceWhenContainedIn:[NSArray arrayWithObject:[UINavigationBar class]]
setBackgroundImage:[UIImage imageNamed:@"imageName"] forState:state barMetrics:metrics]; // 指定修改
自定义类实现UIAppearance
我们可以自定义一个类,并让这个类支持UIAppearance。为此,我们需要做两件事:
- 让我们的类实现UIAppearanceContainer协议
- 如果是在Objective-C中,则将相关的方法用UI_APPEARANCE_SELECTOR来标记。而在Swift中,需要在对应的属性或方法前面加上dynamic。
当然,要让我们的类可以使用appearance(或appearanceWhenContainedInInstancesOfClasses)来获取自己的类,则还需要实现UIAppearance协议。
网友评论