ViewDSL
深受 UIKitDSL 启发,但希望添加一些功能。
您是否知道 Anko?这就是将 DSL 作为一等公民的美妙之处。
CocoaPod
ViewDSL 可通过 CocoaPod 获取!太棒了!
pod "ViewDSL"
约束?
不,ViewDSL 不为您处理约束。它让您选择任何可用的约束方法或者使用其他第三方库。
基本 DSL
使用 ViewDSL,您可以以声明的方式构建 UI。
UIView().add { (v: UIView) in
}
不幸的是,ViewDSL 迫使我们显式声明要添加实例的类型。这并不比 UIKitDSL 好多少。我同意。
让我们看看下面的例子。ViewDSL 为您提供了以一些有趣的方式来初始化您的 UIView 的功能。
class EqualStackView: UIStackView {
func layoutSubviews() {
super.layoutSubviews()
distribution = .fillEqually
spacing = 10
}
}
let stack = EqualStackView { s in
s.axis = .vertical
s.add { (s: EqualStackView) in
s.axis = .horizontal
s.add { (b: UIButton) in
b.setTitle("Yes", for: .normal)
b.backgroundColor = .green
}
s.add { (b: CustomButton) in
b.title = "No"
b.bgColor = .red
}
}
}
这就是 ClosureInit
的力量!但您必须在您的自定义类中实现 init()
方法才能获得它的支持。很有趣,因为所有的 NSObject 类及其派生类都必须实现 init()
,对吧?所以 UIView 类!
ViewDSL请求您显式地声明要添加的实例的类型,这使您有权使所有自定义类都能够无缝与ViewDSL一起工作。当然,您也可以自定义功能使您的DSL更类似Anko或UIKitDSL。
extension ViewDSL {
@discardableResult
func stack(_ closure: (UIStackView) -> Void) -> UIStackView {
return add { (s: UIStackView) in
closure(s)
}
}
}
提供给您UIKitDSL类似实现。但默认情况下并未将其包含在库中。您必须手动将其复制粘贴到您的应用程序中。所有方法前缀为u
,表示它产生UIKit类实例。
DelegatedDSL
您想将您的通用按钮分离出来以供以后重用?遇见DelegatedDSL了!
// Look Here I'm using my custom DSL from previous code
view.stack {
$0.axis = .vertical
// And I want to added by common button to current view
$0.dsl(delegatedTo: blueButton(_:))
}
// I'm using function to put my common button implementation
func blueButton(_ dsl: ViewDSL) {
dsl.add { (b: UIButton) in
b.backgroundColor = .blue
}
}
LayoutBuilderDSL
如果需要将复杂的UI实现放入不同的文件中,此协议将适合您。
class ProfileLayout: LayoutBuilderDSL {
let name: UITextField
let email: UITextField
let saveButton: UIButton
init(name: String, email: String) {
name = UITextField {
$0.text = name
}
email = UITextField {
$0.text = email
}
saveButton = UIButton {
$0.setTitle("Save", for: .normal)
}
}
func layout(_ dsl: ViewDSL) {
dsl.add(name)
dsl.add(email)
dsl.add(saveButton)
}
}
stack.dsl(delegatedTo: ProfileLayout(name: "Egg-boy", email: "[email protected]"))
如果您想使用*.self
样式,可以实现InitializableLayoutBuilderDSL
extension ProfileLayout2: ProfileLayout, InitializableLayoutBuilderDSL {
init() {
super.init(name: "", email: "")
}
}
stack.dsl(withInstanceOf: ProfileLayout2.self)
太棒了!
您也许可以在示例项目中找到它!试试看!
支持第三方库
此库AloeStackView模拟了UIStackView并增加了功能。它是UIScrollView的子类,使得默认的ViewDSL.put(_:)
实现对UIView或UIStackView无效。您应自行支持它。这可能吗?
在进行之前,您可能想阅读这篇帖子Swift中覆盖协议扩展的默认实现
ViewDSL使用动态分发来确定要调用哪种put(_:)
实现。由于协议及其要求都使用@objc,因此我们可以为AloeStackView覆盖put(_:)
extension AloeStaskView {
@objc
public override put(_ view: UIView) {
addRow(view, animated: true)
}
}
view.add { (aloe: AloeStackView) in
aloe.add { (b: UIButton) in
b.setTitle("Click Me!", for: .normal)
}
}