JetLayout
JetLayout 是一个基于 Swift 的布局系统。它具有与 SwiftUI 类似的语法,但 JetLayout 可以与 iOS 11 一起使用。布局引擎基于 Autolayout,因此 JetLayout 的小部件可以轻松地集成到现有的应用中。使用 RxSwift 来连接 UI 和数据。由于所有布局都是用代码编写的,因此可以使用类似于 R.swift 的插件来提供对资源的强类型访问。
要求
iOS 11
Swift 5.2
安装
JetLayout 可通过 CocoaPods 获取。要安装它,只需将以下行添加到您的 Podfile 中
pod 'JetLayout'
示例
要运行示例项目,请克隆存储库,然后先从 Example 目录运行 pod install
用法
布局的示例
VStack(spacing: 8) {
Image(#imageLiteral(resourceName: "Logo"))
Text("Email").addMargin(top: 8)
Field(viewModel.$email)
.contentType(.emailAddress)
.placeholder("[email protected]")
Text("Password").addMargin(top: 8)
Field(viewModel.$password)
.isSecureTextEntry(true)
.placeholder("strong password")
.addMargin(bottom: 24)
Button(type: .system, title: "Sign In")
.corner(radius: 8)
.size(height: 32)
.font(.boldSystemFont(ofSize: 16))
.align(left: 16, right: 16)
}
将现有 UIView 封装到 Widget 中的示例
Widget(UIActivityIndicatorView())
.alignment(.center())
// setup before adding to layout
.setup(block: { view in
view.hidesWhenStopped = true
view.color = .red
})
// UIView hold reference to the dispose bag
.bind(viewModel.$showActivity) { (view, show) in
if (show) {
view.startAnimating()
} else {
view.stopAnimating()
}
}
复杂 UI 可以轻松分为小块
struct AddItemView: View {
let onAddClicked: (String) -> Void
@Observed
private var itemName: String? = "Add new item"
var body: Layout {
HStack(spacing: 16) {
Field(self.$itemName).placeholder("Item mame")
Button(type: .contactAdd)
.disabled(source: self.$itemName.isEmpty)
.tap {
self.onAddClicked(self.itemName ?? "")
self.itemName = ""
}
}
}
}
TableView 示例
struct ItemsTable: View {
let items: Observed<[String]>
var body: Layout {
Table {
// Cells registration
ItemCell.register()
// Static section at top
TSection {
Image(#imageLiteral(resourceName: "Logo"))
.alignment(.fill())
.size(height: 80)
.contentMode(.scaleAspectFit)
}
// Dynamic section
TSection(source: self.items)
}
.preserveParentPadding()
}
}
class ItemCell: ViewBasedTableCell<String> {
override var view: View {
HStack {
Text(self.$model)
}
.preserveParentPadding()
}
}
将组件连接起来并将布局附加到 UIViewController
@Observed
var items: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
title = "Dynamic table view"
VStack(spacing: 24) {
AddItemView { [weak self] in self?.items.append($0) }
ItemsTable(items: self.$items)
}
.root(of: self)
}
视图可以与父视图边界和父视图边距对齐。视图还可以保留父视图边距。
ZStack {
// View 20x20 in the top-right corner. distance to top = 10, distance to rignt = 0
Empty(color: .green, size: CGSize(width: 20, height: 20))
.alignment(Alignment.top().right())
.align(topPadding: true, rightPadding: false)
// this stack alligned to superview's bounds but preserve superview paddings
HStack {
Empty(color: .red)
.align(toPadding: false)
.align(leftPadding: true)
Empty(color: .blue)
.align(bottomPadding: false)
}
.distribution(.fillEqually)
.padding(12) // own padding (at least 12)
.preserveParentPadding() // keep superview padding (result padding: horizontal = 12, vertical = 16)
}
.padding(vertical: 16)
动画示例
@Observed
var termsAccepted = false
VStack(spacing: 8) {
HStack(spacing: 8) {
Text("I accept terms and conditions: ").numberOfLines(2)
Switch(self.$termsAccepted)
}
Button(type: .system, title: "Sign In")
.add(Animation.expanded(self.$termsAccepted))
}
作者
许可协议
JetLayout 以下是 MIT 许可协议。更多信息请参阅 LICENSE 文件。