BRStyle 为 UIKit 提供了一个简单的应用程序风格支持框架。许多应用程序依赖于涉及颜色和字体处理的风格指南。`UIAppearance` 系统支持配置一些基本风格设置,但通常不够用。`BRStyle` 的目标是使使用风格指南更容易。
在具有单个全局风格的简单应用案例中,您将在应用启动时定制一个 BRUIStyle
实例并将其设置为默认全局风格。
BRMutableUIStyle *mutableStyle = [BRMutableUIStyle new];
BRMutableUIStyleColorSettings *colors = [BRMutableUIStyleColorSettings new];
colors.primaryColor = [UIColor blueColor];
// configure more color styles as needed...
BRMutableUIStyleFontSettings *fonts = [BRMutableUIStyleFontSettings new];
fonts.actionFont = [UIFont systemFontOfSize:15];
// configure more font styles as needed...
// when configured, set as the global default
[BRUIStyle setDefaultStyle:mutableStyle];
代码实在太多了,所以 BRUIStyle
支持从 JSON 编码文件加载配置。给定一个具有以下内容的 JSON 文件 style.json
{
"colors" : {
"primaryColor" : "#0000ffff"
},
"fonts" : {
"actionFont" : { "size" : 15 }
}
}
设置代码简化为以下内容
BRUIStyle *style = [BRUIStyle styleWithJSONResource:@"style.json" inBundle:nil];
[BRUIStyle setDefaultStyle:style];
BRStyle 不会试图取代 `UIAppearance`!实际上,您可以使用 BRStyle 作为配置 UIAppearance 代理的方式。例如,当您的应用启动时,您可能会这样做:
// load up style from JSON resource
BRUIStyle *style = [BRUIStyle styleWithJSONResource:@"style.json" inBundle:nil];
[BRUIStyle setDefaultStyle:style];
// configure UINavigationBar and UIToolbar style via UIAppearance
UINavigationBar *bar = [UINavigationBar appearance];
bar.tintColor = style.colors.inverseControlSettings.normalColorSettings.actionColor;
bar.barTintColor = style.colors.navigationColor;
[bar setTitleTextAttributes:@{
NSForegroundColorAttributeName: style.colors.inverseControlSettings.normalColorSettings.actionColor,
NSFontAttributeName: style.fonts.navigationFont,
}];
UIToolbar *toolbar = [UIToolbar appearance];
toolbar.tintColor = bar.tintColor;
toolbar.barTintColor = bar.barTintColor;
实际上,为什么不使用 BRUIStyleAppearanceLoader 辅助类来自动从便利的 styles.json
文件应用外观设置?例如,考虑一个类似以下的简单 BRStyle styles.json
文件:
{
"default" : {
"colors" : {
"primaryColor" : "#ff0000ff",
"backgroundColor" : null
},
"fonts" : {
"actionFont" : { "name" : "Helvetica-Regular", "size" : 12 }
},
"controls" : {
"actionColor" : "#0000ccff",
"borderColor" : "#000000ff",
"glossColor" : "#ffffff33"
}
},
"MyCustomButton" : {
"fonts" : {
"actionFont" : { "name" : "Helvetica-Bold", "size" : 10 }
}
},
"UIPopoverController/MyCustomButton" : {
"fonts" : {
"actionFont" : { "name" : "Helvetica-Bold", "size" : 14 }
}
},
"MyCustomButton-highlighted|selected" : {
"controls" : {
"actionColor" : "#ff00ccff"
}
}
}
这样设置样式:
NSDictionary<NSString *, BRUIStyle *> *styles = [BRUIStyle registerDefaultStylesWithJSONResource:@"styles.json" inBundle:nil];
[[BRUIStyleAppearanceLoader new] setupAppearanceStyles:styles];
`default` 键代表全局默认风格设置。所有其他键代表任意的命名风格,您可以在需要时引用。通过将 styles
字典传递给 `BRUIStyleAppearanceLoader`,键被解释为特定的方式。如果键是符合 `UIAppearance` 并同时符合 `BRUIStylish` 或 `BRUIStylishControl` 的类名,则会在该类上设置 `UIAppearance` 代理的样式。
您可以通过在要美化的类名之前使用斜杠来配置 UIAppearanceContainer
层次结构。在上例中,`MyCustomButton` 类的样式将使用默认的 actionFont
大小为 10,但当包含在 `UIPopoverController` 中时,它将具有大小 14。
您还可以使用符合 BRUIStylishControl
的类为特定的控件状态配置样式,通过在键的末尾附加一个 -
后跟状态名称来实现。可以指定多个状态,通过 |
字符分隔。在上例中,`MyCustomButton` 类在 highlighted
和 selected
状态中对齐。
BRStyle 指定了三个主要的样式属性类别
颜色: BRUIStyleColorSettings
类定义了一系列颜色样式属性,例如 primaryColor
、textColor
、captionColor
等。
字体: BRUIStyleFontSettings
类定义了一系列字体样式属性,例如 actionFont
、textFont
、captionFont
等。
控件颜色: BRUIStyleControlStateColorSettings
类定义了一系列不同控件(按钮)状态的样式属性,如 normalColorSettings
和 highlightedColorSettings
。每个状态都是由一个 BRUIStyleControlColorSettings
类配置的,该类定义了如 actionColor
和 borderColor
等属性。
对于那些迫不及待的人来说,默认情况下 BRStyle 会连接到常见的系统类,如 UIButton
和 UINavigationBar
,并将默认的全局样式应用到它们上。只需将 BRStyle 包含到您的项目中,您就会看到默认的样式应用到各种元素上。
BRStyle 定义了几个特殊的协议,BRStylish
和 BRStylishHost
,用于标记兴趣于被样式化的对象。该协议看起来是这样的
@protocol BRUIStylish <NSObject>
/** A BRUIStyle object to use. If not configured, the global default style should be returned. */
@property (nonatomic, strong, null_resettable) IBOutlet BRUIStyle *uiStyle UI_APPEARANCE_SELECTOR;
@end
@protocol BRUIStylishHost <BRUIStylish>
@optional
/**
Sent to the receiver if the @c BRUIStyle object associated with the receiver has changed.
*/
- (void)uiStyleDidChange:(BRUIStyle *)style;
@end
BRStyle 在 UIBarButtonItem
、UIView
和 UIViewController
上定义了一些核心系统类类别,并为它们全部添加了一个 uiStyle
属性。以下是一个 UIViewController
类别示例
@interface UIViewController (BRUIStyle)
/** A BRUIStyle object to use. If not configured, the global default style will be returned. */
@property (nonatomic, strong, null_resettable) IBOutlet BRUIStyle *uiStyle;
@end
因此,您可以通过简单地引用其 uiStyle
属性来轻松地应用样式到视图层级对象。如果您的视图控制器符合 BRUIStylishHost
,则在视图负载时会在这些控制器上调用 uiStyleDidChange:
方法。
还有一个协议专门用于扩展 UIControl
的类:BRUIStylishControl
。该协议定义了一些控态特定样式的支持,例如在按钮被按下的状态(即在 highlighted
状态)下更改按钮的背景颜色。该协议看起来是这样的
/**
API for objects that act like controls, with style settings based on a UIControlState.
*/
@protocol BRUIStylishControl <NSObject>
/** Manage the BRUIStyleControlStateDangerous state flag. */
@property (nonatomic, getter=isDangerous) IBInspectable BOOL dangerous;
/**
Get a style for a control state. If a style is not defined for the given state, then
the style configured for the @c UIControlStateNormal state should be returned. If no
state is configured for the @c UIControlStateNormal state, then the global default
style should be returned.
@param state The control state.
@return The style associated with the given control state, or the defalut style if
nothing specific configured.
*/
- (BRUIStyle *)uiStyleForState:(UIControlState)state;
/**
Set a style to use for a specific control state.
@param style The style to use.
@param state The control state to apply the style settings to.
*/
- (void)setUiStyle:(nullable BRUIStyle *)style forState:(UIControlState)state UI_APPEARANCE_SELECTOR;
@optional
/**
Notify the receiver that the control state has been updated.
*/
- (void)stateDidChange;
/**
Notify the receiver that the style has been changed for a specific state.
@param style The updated style.
@param state The state the style is associated with.
*/
- (void)uiStyleDidChange:(BRUIStyle *)style forState:(UIControlState)state;
@end
如您所见,它添加了一个新的控制状态 dangerous
,可以用来轻松地样式化执行破坏性操作的按钮。
BRStyle 不仅提供了一种方便的方式从您的应用访问样式属性,而且还能够自动将这些属性应用到您的类中。这种支持来自添加到核心系统类的额外类别,如 UIButton
。以按钮为例,UIButton+BRUIStylishHost
类别使每个按钮都成为 BRUIStylishHost
// UIButton+BRUIStylishHost.h
@interface UIButton (BRUIStylishHost) <BRUIStylishHost>
@end
// UIButton+BRUIStylishHost.m
@implementation UIButton (BRUIStylishHost)
@dynamic uiStyle; // implemented in UIView+BRUIStyle!
- (void)uiStyleDidChange:(BRUIStyle *)style {
const BOOL inverse = ([self nearestAncestorViewOfType:[UINavigationBar class]] != nil || [self nearestAncestorViewOfType:[UIToolbar class]] != nil);
self.titleLabel.font = style.fonts.actionFont;
BRUIStyleControlStateColorSettings *controlSettings = (inverse ? style.colors.inverseControlSettings : style.colors.controlSettings);
[self setTitleColor:controlSettings.normalColorSettings.actionColor forState:UIControlStateNormal];
[self setTitleColor:controlSettings.highlightedColorSettings.actionColor forState:UIControlStateHighlighted];
[self setTitleColor:controlSettings.selectedColorSettings.actionColor forState:UIControlStateSelected];
[self setTitleColor:controlSettings.disabledColorSettings.actionColor forState:UIControlStateDisabled];
}
@end
这种方式,核心界面组件将通过 BRStyle 配置其样式。
如果您愿意自己样式化对象,那么您可以使用 BRStyle/Core
Cocopod 子规范(或者不在项目中包含任何 +BRUIStylishHost
类别)。然后您可以为类实现类,或为现有类添加扩展,这些类遵循 BRUIStylishHost
并在 uiStyleDidChange:
回调中样式化它们。
源代码库中包含的 BRStyleSampler
项目包括一个示例应用,展示了如何使用样式,并提供了简单的编辑功能来修改颜色并查看应用的变化。它还可以从您的样式生成 JSON,这样您就可以将此作为您自己应用程序样式需求的开端。