BRStyle 1.1.0

BRStyle 1.1.0

测试已测试
Lang语言 Obj-CObjective C
许可 Apache 2
发布上次发布2016年6月

Matt Magoffin,wmjesstaylor 维护。



BRStyle 1.1.0

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];

针对❤️UIAppearance

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` 类在 highlightedselected 状态中对齐。

样式属性

BRStyle 指定了三个主要的样式属性类别

  1. 颜色: BRUIStyleColorSettings 类定义了一系列颜色样式属性,例如 primaryColortextColorcaptionColor 等。

  2. 字体: BRUIStyleFontSettings 类定义了一系列字体样式属性,例如 actionFonttextFontcaptionFont 等。

  3. 控件颜色: BRUIStyleControlStateColorSettings 类定义了一系列不同控件(按钮)状态的样式属性,如 normalColorSettingshighlightedColorSettings。每个状态都是由一个 BRUIStyleControlColorSettings 类配置的,该类定义了如 actionColorborderColor 等属性。

应用样式属性

对于那些迫不及待的人来说,默认情况下 BRStyle 会连接到常见的系统类,如 UIButtonUINavigationBar,并将默认的全局样式应用到它们上。只需将 BRStyle 包含到您的项目中,您就会看到默认的样式应用到各种元素上。

深入了解并成为时尚的主持人

BRStyle 定义了几个特殊的协议,BRStylishBRStylishHost,用于标记兴趣于被样式化的对象。该协议看起来是这样的

@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

BRStyleUIBarButtonItemUIViewUIViewController 上定义了一些核心系统类类别,并为它们全部添加了一个 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,这样您就可以将此作为您自己应用程序样式需求的开端。