IBKit
Swift 中的声明式界面构建器。
var body: Interface {
ViewGroup {
UIImageView()
.assign(to: \Self.thumbnailImageView, on: self)
UIView {
UILabel()
.font(.preferredFont(forTextStyle: .title2))
.textColor(.label)
UILabel()
.font(.preferredFont(forTextStyle: .caption1))
.textColor(.secondaryLabel)
.assign(to: \Self.additionalTextLabel, on: self)
UIImageView()
.image(UIImage(named: "ic_passenger")?.withRenderingMode(.alwaysTemplate))
.tintColor(.secondaryLabel)
UILabel()
.font(.preferredFont(forTextStyle: .caption1))
.textColor(.secondaryLabel)
}
.backgroundColor(.systemBackground)
PriceView()
UIView()
.backgroundColor(.separator)
}
}
为何选择 IBKit
Storyboard, XIB 是一种 XML 文件。然而,你是否亲手编辑过 storyboard 或 XIB?可能没有。阅读和编辑很难。Storyboard 和 XIB 具有许多麻烦的特性,如 id
、destination
等。此外,它们包含相当大量的 XML。因此,当有人打开带有其修改的 pull request 时,人们无法看到发生了哪些更改。
更糟的是,Storyboard 随着时间的推移会不断变大。它们可能一开始很小,但当你添加了另一个视图控制器,再添加另一个,然后再添加另一个,突然你就意识到你在一个文件中有了十个屏幕的数据,任何源控制更改都会变得非常痛苦。
此外,Interface Builder 对 Swift 代码和反之亦然的了解不多。这使得有很多不安全的功能。例如,我们从 IB 拖动到我们的代码中连接某个功能。那么如果我们从代码中删除了该功能怎么办?代码仍然可以编译通过,但程序会崩溃!
最后,Interface Builder 的行为并不像预期的那样。从 xib 设置的命名颜色在 viewDidLoad
、viewWillAppear
、awakeFromNib
方法中不能更改。
尽管如此,Storyboard, XIB 有强大的优势。它提供了非常好的视觉表示。而且使用简单。当你以编程方式创建 ViewController 时,会有很多代码而且看起来很冗长。
基本上,IBKit 是一种用于程序化 UI 的工具。通过使用声明式风格,您可以直观地理解 UI。此外,IBKit 有一个简单的 Preview
类用于 Xcode 预览。您可以轻松地提供实时视觉表示。
IBKit 是实现 UI 的最直接、最简单的方式。
要求
- Xcode 11+
- Swift 5.1
- iOS 10
安装
IBKit
不包含任何外部依赖。目前支持以下选项
Cocoapods
# Podfile
user_framework!
target 'YOUR_TARGET_NAME' do
pod 'IBKit'
end
替换 YOUR_TARGET_NAME
,然后在 Podfile
目录中输入
$ pod install
使用 Cocoapods 安装 IBKit 需要 11.0+ 的部署目标。
Swift 包管理器
创建一个 Package.swift
文件。
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "NAME",
dependencies: [
.package(url: "https://github.com/IBCodeKit/IBKit.git", from: "SEMVER_TAG")
],
targets: [
.target(name: "NAME", dependencies: ["IBKit"])
]
)
替换 SEMVER_TAG
然后输入
$ swift build
或者
在 XcodeProject 中,打开 File
> Swift Packages
> Add Package Dependency..
然后输入 https://github.com/IBCodeKit/IBKit.git
使用方法
遵守 InterfaceBuilder
协议。
class PriceView: UIView, InterfaceBuilder {
var body: Interface {
...
}
}
在主体中声明用户界面。
ViewGroup {
UIImageView()
.assign(to: \Self.thumbnailImageView, on: self)
UIView {
UILabel()
.font(.preferredFont(forTextStyle: .title2))
.textColor(.label)
UILabel()
.font(.preferredFont(forTextStyle: .caption1))
.textColor(.secondaryLabel)
.didAwakeFromBuilder { views in
views.this.topAnchor.constraint(equalTo: views.superview.topAnchor).isActive = true
views.this.trailingAnchor.constraint(equalTo: views.superview.trailingAnchor).isActive = true
}
}
.backgroundColor(.systemBackground)
}
使用 loadFromIB
方法实例化您的视图(控制器)。
let view = PriceView.loadFromIB()
或者使用 build
方法加载主体。
override init(frame: CGRect) {
super.init(frame: frame)
build()
}
Xcode 预览
-
要使用 Xcode 预览,您的项目中必须弱导入 SwiftUI 框架。
在 XcodeProject 中,打开
Build Phases
>Link Binary With Libraries
> 添加SwifTUI
> 将 SwiftUI 状态更改为Optional
-
遵守
PreviewProvider
协议。
#if canImport(SwiftUI) && DEBUG
import SwiftUI
@available(iOS 13.0, *)
struct PriceView_Preview: PreviewProvider {
...
}
#endif
- 使用
Preview
类实现PreviewProvider
协议。
static var previews: some View {
Preview(view: PriceView.loadFromIB())
}
贡献
欢迎提交代码请求和错误报告!
请随时提交代码请求。