基于facebook/yoga实现一个类似swiftui和Flutter的声明式UI框架
- iOS 10.0+
- Xcode 12.5
- Swift 5.4
pod 'FlexLayoutKit', '~> 0.4'
以下可选
pod 'FlexLayoutKit/SDWebImage'
pod 'FlexLayoutKit/Kingfisher' #需要ios 12以上
- FlexBox布局
- 声明式语法,类似SwiftUI,如HStackView、VStackView、ZStackView,类似Flutter中的Row、Column、Stack、Wrap
- 自动计算UITableViewCell 高度
- 支持VScrollView、HScrollView,自动计算contentSize
- 使用Wrap轻松实现流式布局,超过屏幕时会自动换行
- Forin和if else DSL支持
- 数据驱动UI,更新数据后自动会更新UI
- 支持百分比
- 链式语法
import FlexLayoutKit //1.导入FlexLayoutKit
import UIKit
//2.继承FlexboxBaseViewController
class ViewController: FlexboxBaseViewController
{
override func viewDidLoad() {
super.viewDidLoad()
}
//3.重写bodyView
@FlexboxViewBuilder override func bodyView() -> [FlexboxView] {
return HStackView(mainAxis: .center, crossAxis: .center) {
Text("Hello FlexLayoutKit")
}
.flex(1)
}
}
or
import FlexLayoutKit
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
view.flex.mainAxis(.center).crossAxis(.center).addItems {
HStackView(mainAxis: .center, crossAxis: .center) {
Text("Hello FlexLayoutKit")
}
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view.flex.applyLayout()
}
}
HStackView {
ZStackView {
ImageView()
.backgroundColor(UIColor.gray.withAlphaComponent(0.5))
.cornerRadius(8)
.left(0)
.bottom(0)
.size(width: 50, height: 50)
Text("1")
.fontSize(12)
.textColor(.white)
.right(0)
.top(0)
.size(16)
.cornerRadius(8)
.backgroundColor(.red)
.textAlignment(.center)
}
.size(58)
.margin(.right, 8)
VStackView(mainAxis: .spaceAround) {
HStackView(crossAxis: .center) {
Text("Leo")
.fontSize(16, weight: .bold)
.expanded()
Text("13:30")
.fontSize(12, weight: .medium)
.textColor(.gray)
}
Text("hello,nice to meet you")
}
.height(50)
.expanded()
.margin(.top, 8)
}
.padding(.horizontal, 15)
.margin(.top, 100)
HStackView {
ImageView().size(40).cornerRadius(10).backgroundColor(.gray.withAlphaComponent(0.2))
Spacer(10)
Text("Leo").textColor(.orange).fontSize(16,weight: .medium)
}
VStackView(crossAxis: .center) {
ImageView().size(40).cornerRadius(10).backgroundColor(.gray.withAlphaComponent(0.2))
Spacer(10)
Text("Leo").textColor(.orange).fontSize(16,weight: .medium)
}
ZStackView {
FlexContainer(mainAxis: .center, crossAxis: .center){
Text("99")
}
.cornerRadius(15)
.backgroundColor(.red)
.top(0)
.right(0)
.size(30)
}
.size(100)
.backgroundColor(.orange)
let tags = ["tag1","tag2","tag3","tag4","tag5","tag6","tag7","tag8","tag9"]
//gap 是行间距和列间距简写
Wrap(gap: 10){
for tag in tags {
Text(tag)
.backgroundColor(.gray.withAlphaComponent(0.5))
.textAlignment(.center)
.cornerRadius(15)
.padding(.horizontal,10)
.height(30)
.onTap {
print(tag)
}
}
}
VScrollView {
for i in 0...100 {
FlexContainer(mainAxis: .center, crossAxis: .center) {
Text("\(i)")
}
.height(60)
.backgroundColor(.orange.withAlphaComponent(0.1))
.margin(.vertical,5)
}
}
let state = true
HStackView {
if state {
Text("true")
}else{
Text("false")
}
}
@UState var count: String = "count"
var step: Int = 0 {
didSet{
count = "count = \(step)"
}
}
VStackView(mainAxis: .center, crossAxis: .center) {
Text($count).textColor(.black)
Button("add").margin(.top,10).backgroundColor(.blue).onTap { [unowned self] in
self.step = self.step + 1
//修改内容后,要重新布局
self.updateFlexLayout()
}
}
Text("FlexPercent").backgroundColor(.orange).width(20%).height(20%)
1)cell继承TableDynamicCell
2)UITableView的rowHeight设置为UITableView.automaticDimension
class CellItem: TableDynamicCell {
@FlexboxViewBuilder override func bodyView() -> [FlexboxView] {
return VStackView {
...
}
}
}
UITableView().flex.expanded().apply {
$0.delegate = self
$0.dataSource = self
$0.register(CellItem.self, forCellReuseIdentifier: "cellID")
$0.estimatedRowHeight = 80
$0.rowHeight = UITableView.automaticDimension
}
UILabel()
.modifier
.text("链式语法")
.textColor(.orange)
.font(.systemFont(ofSize: 16))
等同于
let label = UILabel()
label.text = "test apply"
label.font = .systemFont(ofSize: 16)
label.textColor = .orange
只在UIView有效
UIView(frame: CGRect(x: 10, y: 100, width: 60, height: 60)).apply {
$0.backgroundColor = .blue
$0.layer.cornerRadius = 30
$0.clipsToBounds = true
}
UILabel().apply { label in
label.text = "test apply"
label.font = .systemFont(ofSize: 16)
label.textColor = .orange
}
等同于
let blueView = UIView(frame: CGRect(x: 10, y: 100, width: 60, height: 60))
blueView.backgroundColor = .blue
blueView.layer.cornerRadius = 30
blueView.clipsToBounds = true
let label = UILabel()
label.text = "test apply"
label.font = .systemFont(ofSize: 16)
label.textColor = .orange
-
主轴方向
-
布局方向 ltr,rtl
-
主轴方向子项分布 mainAxis
-
次轴方向子项分布 crossAxis
-
次轴方向多行子项分布
-
子项自身分布
-
flexbox文档
- justifyContent
- alignContent
- alignItems
- alignSelf
- flexDirection
- direction
- flexWrap
- position
- margin padding left right top bottom
- size width height minWidth
- flex 属性
- applyLayout
- markDirty
- sizeThatFits
- numberOfChildren
- isIncludedInLayout
- enabled
- display
- HStackView = Row
- VStackView = Column
- ZStackView = Stack 与Flutter和SwiftUI有差异,需要自己定义好size才有效果
- Wrap
- Text
- ImageView
- Space
- TextField
- TextView
- ScrollView
- VScrollView
- HScrollView
- TabCell
- TableDynamicCell
- CollectionCell
对于没有第二次封装的UIVIew,可以使用以下方法进行布局
UILabel().flex.makeLayout {
$0.margin(.left, 10).margin(.top, 100)
}.apply {
_ = $0.modifier
.text("flex.makeLayout写法")
.font(.systemFont(ofSize: 18))
.textColor(.orange)
}
var blowUp = false
let boxView = FlexContainer()
VStackView(mainAxis: .center, crossAxis: .center) {
boxView.flex.size(100).modifier.backgroundColor(.blue)
Button("动画").size(width: 100, height: 30)
.backgroundColor(.orange).margin(.top,10)
.onTap { [unowned self] in
UIView.animate(withDuration: 0.25, delay: 0) {
self.boxView.flex.size(self.blowUp ? 200 : 100)
self.updateFlexLayout()
self.blowUp = !self.blowUp
}
}
}
- 双向绑定
- UITableView封装 ListView ListItem
- UICollection封装 GridView H V
- 瀑布流
- 测试
- 支持SPM
- https://github.com/MihaelIsaev/UIKitPlus
- https://blog.eppz.eu/declarative-uikit-with-10-lines-of-code/
- https://github.com/hmlongco/RxSwiftWidgets
- https://tech.youzan.com/-sheng-ming-shi-uikitzai-you-zan-mei-ye-de-shi-jian/
- https://github.com/sakiyamaK/DeclarativeUIKit
- https://github.com/hmlongco/Builder/tree/main
- https://github.com/hainayanda/Draftsman
- https://github.com/nicklockwood/layout xml实现布局
- https://kazaimazai.com/swifty-uikit/
- https://github.com/KazaiMazai/SwiftyUIKit
- https://github.com/zhenglibao/FlexLib
- https://github.com/layoutBox/FlexLayout
- https://github.com/pujiaxin33/StackUI
FlexLayoutKit is under MIT license. See the LICENSE file for more info.