🎨
Stylist
Stylist 允许你在可热重新加载的外部 yaml 或 json 主题文件中定义 UI 样式
✅ 在 外部主题文件 中定义样式✅ 通过 编程方式 或通过 Interface Builder 应用样式✅ 热加载 主题,立即查看结果而无需重新编译✅ 将样式应用于任何 UIView,UIViewController,UITabBar 以及你自己的 自定义 类✅ 通过样式 名称 或 类名 应用样式✅ 在特定视图 层次结构 中应用样式✅ 实时 切换 整个主题✅ 为所有流行的 UIKit 类内置样式属性✅ 引用 主题变量 以获取常用值✅ 在 其他样式 中包含样式✅ 定义 自定义 强类型属性和自定义解析以动态设置任何属性
示例主题
variables:
primaryColor: "DB3B3B" # hex color
headingFont: Ubuntu # reference loaded font
styles:
MyApp.MyViewController: # applied to MyViewController class
view: # access the view
tintColor: $primaryColor # reference a variable
navigationBar: # access the navigation bar
barTintColor: red # use color name
titleColor: white
UIButton:
backgroundImage: buttonBack # set image
backgroundImage:highlighted: buttonBack-highlighted # for highlighted control state
MyApp.Section:
styles: [themed] # include other styles
axis(horizontal:regular): horizontal # restrict by size class
axis(horizontal:compact): vertical
MyApp.Section UIStackView UILabel: # View containment selector
textAlignment: right # use enums
primaryButton:
textColor: "55F" # shorted hex value
contentEdgeInsets: [10,5] # set simplified UIEdgeInsets
font(device:iphone): $headingFont:16 # reference font variable and change size
font(device:ipad): $headingFont:22 # restrict to device
secondaryButton:
cornerRadius: 10 # set layer properties
textColor: customColor # use named color
font: 20 # use system font
contentEdgeInsets: 6 # set UIEdgeInsets using a single value
sectionHeading:
font: title 2 # use UIFontTextStyle
font: darGray:0.5 # built in color with alpha
content:
font: Arial:content # Use custom font with UIFontTextStyle
themed: # style is referenced in other styles
tintColor: $primaryColor
⬇️ 安装
Cocoapods
添加以下内容到你的 podfile
pod 'Stylist'
Carthage
添加以下内容到你的 Cartfile
github "yonaskolb/Stylist"
⚒ 用法
确保导入Stylist
import Stylist
加载主题
要加载一个主题,请使用以下方法:
Stylist.shared.load(path: pathToFile)
您可以加载多个主题,只要它们的路径不同,所有主题都会被应用。
您还可以手动加载一个主题,然后通过名称添加它,这样您就可以在运行时切换主题。
let theme = try Theme(path: pathToTheme)
Stylist.shared.addTheme(theme, name: "mainTheme")
设置样式
当类样式被添加到一个superview中时,它们将应用于UIView
;当调用viewDidLoad()
时,它们将应用于UIViewController
。
要在一个可定制的类上设置自定义样式,只需设置它的style
属性。您可以通过逗号分隔来设置多个样式。
编程方式
myView.style = "myStyle"
otherView.style = "myStyle,otherStyle"
界面构建器
您可以在属性检查器中设置Interface Builder中的样式
热重载
您可以选择监视主题文件,这意味着每当该文件被更改时,样式将被重新加载。这些更改也可以被动画化!
主题可以位于远程URL,允许您远程更新样式。
热加载在开发期间非常有用,因为您可以在不重新编译的情况下动态更改样式,并立即看到结果动画!要监视文件,只需在stylist上调用的watch
,并传递一个本地磁盘上的文件URL或远程URL。
Stylist.shared.watch(url: fileOrRemoteURL, animateChanges: true) { error in
print("An error occurred while loading or parsing the file: \(error)")
}
如果在任何时候发生错误,带有ThemeError
的parsingError
回调将被调用,这将确切地告诉您出什么问题,包括任何格式错误或不正确的引用。这意味着如果您不小心保存了无效的主题,您不必担心您的应用程序会崩溃。
要停止监视文件,您可以在返回的FileWatcher
上调用stop()
。
请注意,如果某个样式属性已存在,然后您将其删除,风格师无法撤回更改,因此该属性将保留在之前的状态。
🎨 主题
主题文件包含一个变量
列表和一个样式
列表。变量可以使用$variableName
在样式中进行引用。
variables:
primaryColor: "DB3B3B"
styles:
primary:
color: $primaryColor
样式选择器
样式使用一个或多个选择器定义。选择器可以是类或样式名称,或两者兼有。自定义类必须以前缀模块名称。样式名称必须以小写字母开头。
例如
UIButton
所有的 UIButtonsMyApp.MyView
MyApp 模块中所有的 MyView 类UITabBar.primary
所有应用主要样式的标签栏primary
所有应用主要样式的可样式元素
可以选择器可以有多个,用空格分开,然后检查后续选择器是否包含在先前的选择器中。这仅适用于 UIViews 和 UIViewControllers。容器不必是直接的超视图,也可以是更上层的响应者链。
例如,以下样式将应用于任何位于带有 section
样式的视图中的 UIButton
,该视图位于带有 main
样式的 UIStackView
中,然后位于 UINavigationController
中。
styles:
UINavigationController UIStackView.main section UIButton:
font: title3
样式将按照特定性顺序应用,因此,样式越具体(选择器越多),则应用越晚。
样式引用
每个样式还可能有一个包含其他继承样式的styles
数组,其属性也会应用,而不覆盖任何内容。
styles:
primary:
styles: [themed]
themed:
tintColor: red
backgroundColor: EEEEEE
视图层次结构样式
样式可以引用视图层次结构,然后使用其自己的属性来设置样式。这对于测试或轻松访问视图层次结构的各个部分非常有用(例如 UIViewController.view
)
以下类型可以使用子样式
- UIView
superview
:超视图next
:下一个同级视图previous
:前一个同级视图viewController
:视图所属的视图控制器
- UIViewController
view
:根视图parent
:父视图控制器navigationController
:包含此视图的UINavigationControllertabBarController
:包含此视图的UITabBarControllertabBar
:此视图控制器的UITabBar。可以在任何子视图控制器中访问navigationBar
: 当前视图控制器的导航栏。任何子视图控制器都可以访问。
styles:
MyApp.MyViewController:
view:
tintColor: red
navigationBar:
tintColor: red
样式上下文
样式属性可以被限制到特定的上下文中,例如某种控件状态或特征集合。这与 CSS 媒体查询的工作方式类似。详见 上下文。
styles:
UIButton.primary:
backgroundImage: buttonBack
backgroundImage:highlighted: buttonBack-highlighted
UIStackView.main:
axis(horizontal:regular): horizontal
axis(horizontal:compact): vertical
title:
font(device:iphone): $headingFont:16
font(device:ipad): $headingFont:22
🖍 样式属性
许多 UIKit 视图和工具栏按钮都内置了可以设置的属性。可以在 样式属性 中查看这些属性。
⚙️ 自定义属性
也可以添加自定义属性和解析器,以便以强类型的方式配置所需的内容。
要创建一个 StyleProperty
,传递一个名称和一个设置属性的泛型闭包。确保为可样式的类和泛型 PropertyValue
提供类型。
// creates a new property that is applies a TextTransform to a MyLabel
// access the property context and value via the PropertyValue
let property = StyleProperty(name: "textTransform") { (view: MyLabel, value: PropertyValue<TextTransform>) in
view.textTransform = value.value
}
// adds the custom property to Stylist
Stylist.shared.addProperty(property)
值必须遵守 StyleValue
协议,这是一个简单的协议。
public protocol StyleValue {
associatedtype ParsedType
static func parse(value: Any) -> ParsedType?
}
PropertyValue
将包含包含您解析的值的 value
属性。它还有一个 context
,包含诸如设备类型、UIControlState、UIBarMetrics、尺寸类别等的 属性上下文。
当加载主题或在一个视图上设置样式时,如果视图类型和属性名称匹配,将应用这些自定义属性。
已经支持许多不同类型的属性,并在样式属性类型中列出。
⚙️ 自定义可样式类
默认情况下,UIView
、UIViewController
和 UIBarItem
可以被样式化。您也可以通过响应 Styleable
协议将任何自定义类设置为可样式化的。内置的 Styleable
类会自动调用 applyStyles
,因此您必须在 styles
设置器中自动执行此操作。
public protocol Styleable: class {
var styles: [String] { get set }
}
extension Styleable {
func applyStyles() {
Stylist.shared.style(self)
}
}
👥 贡献者
此工具由以下机构支持:
👤 贡献
欢迎提交拉取请求和问题。
📄 许可证
Stylist 根据 MIT 许可证授权。详情请参阅 LICENSE。