Gestalt 是一个非侵入式和轻量级的框架,用于应用主题化,并支持动画主题切换。
假设你想为一个带有单个标签的视图控制器设置主题
import Gestalt
struct Theme: Gestalt.Theme {
let view: ViewTheme = .init()
static let light: Theme = .init(view: .light)
static let dark: Theme = .init(view: .dark)
}
struct ViewTheme: Gestalt.Theme {
let font = UIFont.preferredFont(forTextStyle: .headline)
let color: UIColor
let backgroundColor: UIColor
static let light: Theme = .init(
color: UIColor.black
backgroundColor: UIColor.white
)
static let dark: Theme = .init(
color: UIColor.white
backgroundColor: UIColor.black
)
}
// In `AppDelegate.application(_:didFinishLaunchingWithOptions:)`
// assign a default theme (or user's choice from user defaults):
ThemeManager.default.theme = Theme.light
class ViewController: UIViewController {
@IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.observe(theme: \Theme.view)
}
}
extension ViewController: Themeable {
typealias Theme = ViewTheme
func apply(theme: Theme) {
self.view.backgroundColor = theme.backgroundColor
self.label.textColor = theme.color
self.label.font = theme.font
}
}
调用 self.observe(theme: \Theme.view)
会将接收器注册到 ThemeManager.default
以进行主题观察,以便在未来主题更改时接收通知,并立即调用一次。 首次调用没有动画效果,但之后的所有更改都将具有动画效果。
要更改当前主题(即使在应用程序运行时),只需将不同的主题分配给您正在使用的 ThemeManager
。
ThemeManager.default.theme = Theme.dark
这将导致给定 ThemeManager
上所有先前注册的闭包再次被调用。
请参阅 GestaltDemo
目标以获取更真实/详细的用法示例。
ThemeManager.default
就足够了。 但是,也可以通过 let manager = ThemeManager()
创建专用的 ThemeManager
。在视图已经加载后使用外观代理时,此库使用了一种技巧,即从主窗口中移除并重新添加应用程序的根视图以激活代理。 这在 App Extensions 中是不可能的,例如 Today 小部件,因为扩展安全 API 限制了对主窗口的访问。 因此,要在 App Extensions 中使用此库,您需要在设置主题后,通过在根视图控制器中添加类似这样的代码来手动触发根视图的重新加载。
ThemeManager.default.observe(theme: Theme.self) { [weak self] _ in
if let strongSelf = self, let superview = strongSelf.view.superview {
strongSelf.view.removeFromSuperview()
superview.addSubview(strongSelf.view)
}
}
func apply(theme: Theme)
的主体应该是 幂等 的,以避免在重复调用时产生不必要的副作用。推荐将 Gestalt 添加到项目的方式是通过 Carthage
github 'regexident/Gestalt' ~> 2.0.0
或者通过 Cocoapods
pod 'Gestalt', '~> 2.0.0'
let package = Package(
name: "GestaltDemo",
dependencies: [
.package(url: "https://github.com/regexident/Gestalt.git", from: "2.0.0")
],
targets: [
.target(name: "GestaltDemo", dependencies: [ "Gestalt" ])
]
)
Gestalt 在 MPL-2.0 许可证下可用。 有关更多信息,请参阅 LICENSE
文件。