StackUI
像 SwiftUI
一样使用 UIStackView
。
使用 @propertyWrapper
、@resultBuilder
、链式语法以及 SwiftUI
中使用的其他特性,使 UIStackView
更容易使用。对于如 Label
、Button
和 ImageView
这样的类,仍然使用 UIKit,但通过链式语法进行了封装。
由于 SwiftUI
需要 iOS 13+ 系统才能使用,因此几乎不可能在实际项目中使用 SwiftUI
。但 SwiftUI
的特性确实很吸引人,所以 StackUI
是在 UIStackView
范围内实现的 SwiftUI
。您可以在 StackUI
中体验一些 SwiftUI
的特性,这样您就可以尽早学习新特性。
如果您厌倦了配置 UIKit 的约束,那么 StackUI
将为您提供很好的帮助。声明式布局让世界更美好。
特性
- 类似
SwiftUI
的声明式语法; - 数据驱动 UI,更新数据后 UI 自动更新;
- 支持
HScrollStack
、VScrollStack
,当内容超出堆栈的宽度和高度时,自动开启滚动; - 链式语法配置 UIKit;
- 可以灵活扩展自定义类以支持
StackUI
;
要求
- iOS 9.0+
- XCode 13.0+
- Swift 5.4+
安装
CocoaPods
target'<Your Target Name>' do
pod'StackUI'
//If you want to use RxSwift
pod'StackUI/RxSwift'
end
首先执行 pod repo update
,然后执行 pod install
SPM
- 文件 > Swift 包 > 添加包依赖
- 添加 https://github.com/pujiaxin33/StackUI.git
- 使用 "0.0.5" 选择 "到下一个主要版本"}
- 如果您想使用
RxSwift
特性,选择StackUISwithRxSwift
产品
示例
HStack
HStack(alignment: .center, spacing: 5) {
ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
Label("user nickname").font(.systemFont(ofSize: 18, weight: .medium))
}
VStack
VStack {
Label("user nickname").font(.systemFont(ofSize: 18, weight: .medium))
Label().text("The user is lazy, nothing left!").font(.systemFont(ofSize: 12)).textColor(.gray)
}
HScrollStack
和 ForIn
var users = [UserModel]()
for index in 0...25 {
let model = UserModel(avatar: "avatar", name: "user\(index)", desc: "user description\(index)")
users.append(model)
}
HScrollStack() {
for model in users {
HStack(alignment: .center, spacing: 5) {
Spacer(spacing: 12)
ImageView().image(UIImage(named: model.avatar)).size(width: 80, height: 80)
VStack {
Label(model.name).font(.systemFont(ofSize: 18, weight: .medium))
Label().text(model.desc).font(.systemFont(ofSize: 12)).textColor(.gray)
}
Divider()
}.size(width: 300)
}
}
@Live
在属性前添加 @Live
,在使用时添加 $
前缀。在更新属性时,关联的 UIKit 会自动更新界面。
//definition
@Live var nickName: String? = "User nickname"
@Live var desc: String? = "The user is lazy, and nothing is left!"
//use
HStack(distribution: .equalCentering, alignment: .center) {
HStack(alignment: .center, spacing: 5) {
ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
VStack {
Label($nickName).font(.systemFont(ofSize: 18, weight: .medium))
Label().text($desc).font(.systemFont(ofSize: 12)).textColor(.gray)
}
}
ImageView().image(UIImage(named: "arrow_right"))
}
//update
nickName = "Jay Chou"
desc = "Ouch, not bad ❤️"
RxSwift
的 Driver
//definition
var nickName = PublishSubject<String?>()
var desc = PublishSubject<String?>()
//use
HStack(distribution: .equalCentering, alignment: .center) {
HStack(alignment: .center, spacing: 5) {
ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
VStack {
Label(nickName.asDriver(onErrorJustReturn: nil)).font(.systemFont(ofSize: 18, weight: .medium))
Label().text(desc.asDriver(onErrorJustReturn: nil)).font(.systemFont(ofSize: 12)).textColor(.gray)
}
}
ImageView().image(UIImage(named: "arrow_right"))
}
//update
nickName.onNext("Jay Chou")
desc.onNext("Ouch, not bad ❤️")
自定义视图支持 StackUI
您可以自定义父类
从 View
、Label
等继承,然后扩展自定义属性。
class CustomView: View {
var customColor: UIColor = .black
func customColor(_ customColor: UIColor) -> Self {
self.customColor = customColor
self.backgroundColor = customColor
return self
}
}
class CustomLabel: Label {
var customColor: UIColor = .black
func customColor(_ customColor: UIColor) -> Self {
self.customColor = customColor
self.textColor = customColor
return self
}
}
如果语句
var isShowInfo: Bool = false
HStack(distribution: .equalCentering, alignment: .center) {
HStack(alignment: .center, spacing: 5) {
ImageView().image(UIImage(named: "avatar")).size(width: 40, height: 40)
if self.isShowInfo == true {
VStack {
Label("User nickname").font(.systemFont(ofSize: 18, weight: .medium))
Label().text("The user is lazy, nothing left!").font(.systemFont(ofSize: 12)).textColor(.gray)
}
}else {
Label("No Information")
}
}
ImageView().image(UIImage(named: "arrow_right"))
}
父类不可修改,则符合协议
符合如 StackUIView
和 StackUILabel
的协议,然后扩展自定义属性。
class CustomViewFromProtocol: UIView, StackUIView {
var customColor: UIColor = .black
func customColor(_ customColor: UIColor) -> Self {
self.customColor = customColor
self.backgroundColor = customColor
return self
}
}
class CustomLabelFromProtocol: UILabel, StackUILabel {
var customColor: UIColor = .black
func customColor(_ customColor: UIColor) -> Self {
self.customColor = customColor
self.textColor = customColor
return self
}
}
链式语法暂不支持属性配置
通过应用闭包进行统一配置
HStack(alignment: .center, spacing: 5) {
Label().text(model.desc).apply {label in
//If there are attributes that are not defined by the chain syntax, they can be configured in the apply closure, or they can be submitted to Issue for support.
label.font = UIFont.systemFont(ofSize: 10)
label.textColor = .gray
}
}
ViewBox
使用
有时视图需要外边距。此时,您可以将在 ViewBox 中的视图,并设置填充,这样就可以间接设置视图的上、下、左、右边距。如下代码所示:Label 的边距为 top: 10, left: 20, bottom: 10, right: 20
。
ViewBox(paddings: .init(top: 10, left: 20, bottom: 10, right: 20)) {
Label("Hobbies: writing code;").font(. systemFont(ofSize: 15)).numberOfLines(0)
}.backgroundColor(.lightGray)
当前支持的类
Layer
:在View
类中配置Layer
的相关属性View
ImageView
Control
Label
Button
TextField
文本视图
步进器
切换UI
页面控制
滑动条
间隔空间
分隔线
活动指示器
滚动视图
表格视图
收集视图
如果需要支持其他类和属性,请提交问题或拉取请求。