CellKit 是一个 Swift 包,它简化了在 UITableView 和 UICollectionView 中使用 cell 的工作流程。无需再注册 cell 类或 XIB,无需再出队 cell 并设置其视图模型。CellKit 会处理这一切。
将以下行添加到你的 Swift Package 依赖项中,或者在 Xcode 中,转到File -> Swift Packages -> Add Package Dependency
,然后输入此仓库的 URL 地址。
.package(url: "https://github.com/futuredapp/CellKit", from: "0.8.1")
(可选)你可以添加 DiffableCellKit
。
将以下行添加到你的 Podfile
中,然后运行 pod install
pod 'CellKit', '~> 0.8'
(可选)你可以添加 DiffableCellKit
子规范
pod 'CellKit', '~> 0.8', subspecs: ['Diffable']
CellKit 提供了一个数据源和一个 section 模型,你可以用你的 cell、header 和 footer 模型来填充它们。 你需要做的就是定义你的 cell 视图和你的 cell 模型,并使其遵循 CellConvertible 和 CellConfigurable 协议,CellKit 将处理其余的事情。
CellKit 提供了 CellModelDataSource
和 GenericCellModelSection
,它们定义了你的 UITableView
/UICollectionView
cell 结构。你可以随时继承 CellModelDataSource
并覆盖其方法来满足你的需求。
这是一个典型的 CellKit 数据源用法示例
let dataSource = CellModelDataSource([
GenericCellModelSection(arrayLiteral:
PrototypeCellViewModel(name: "Prototype")
),
GenericCellModelSection(arrayLiteral:
CodeCellViewModel(name: "Code")
),
GenericCellModelSection(arrayLiteral:
XIBCellViewModel(name: "XIB")
)
])
tableView.dataSource = dataSource
collectionView.dataSource = dataSource
CellKit 支持各种 cell 声明方式,包括 .xib
文件,UITableView
界面构建器原型 cell 和完全用代码编写的 cell。
请注意,你的 .xib
文件、Cell 子类和 Cell 标识符必须具有相同的名称。 可以不使用相同的标识符,但不建议这样做。
专业提示:你可以使用我们的 自定义模板只需点击几下即可生成带有 CellKit 协议的 Cell。
为了使你的 cell 和 cell 视图模型能够与 CellKit 一起工作,它们必须遵循以下协议
这是你的Cell的协议。 此协议提供了一个 configure(model:)
方法,当 tableview 请求可重用 cell 时,该方法会被调用,并用于将你的模型分发到你的 cell。
class XIBCell: UITableViewCell {
@IBOutlet private weak var label: UILabel!
}
extension XIBCell: CellConfigurable {
func configure(with model: XIBCellViewModel) {
label.text = model.name
}
}
你的 cell 模型的协议。 使用此协议指定你的 cell 配置,例如高度、xib 位置、cell 是否可高亮显示等。
struct PrototypeCellViewModel {
let name: String
}
extension PrototypeCellViewModel: CellModel {
var usesNib: Bool { false }
var registersLazily: Bool { false }
}
这是一个方便的表,其中包含可配置属性及其默认值,你可以在其中提供自己的值。
属性 | 数据类型 | 默认值 | 描述 |
---|---|---|---|
registersLazily | Bool | true | 指示数据源是否应将视图注册到其呈现视图。 |
usesNib | Bool | true | 指示 cell 是否在 .xib 文件中定义 |
nib | UINib? | 带有 cellClass 名称的 xib。 如果 usesNib 为 false,则为 nil。 |
包含你的视图的 .xib 文件的 UINib 引用 |
cellClass | AnyClass | 对视图类的类引用。 | |
reuseIdentifier | String | 一个唯一的重用标识符 | |
cellHeight | Double | 44.0 | cell 的高度 |
highlighting | Bool | true | 指示 cell 是否可以被高亮显示 |
separatorIsHidden | Bool | false | 指示是否应隐藏分隔符 |
此协议使用关联类型扩展了 CellModel,因此可以根据类型的名称提供默认的 cellClass
和 reuseIdentifier
值。
当你在 XIB 中声明你的 cell 时,它特别方便,因为你所需要做的就是定义其关联类型,CellKit 将提供其余的一切。
这是一个例子
class XIBCell: UITableViewCell, CellConfigurable {
@IBOutlet private weak var label: UILabel!
func configure(with model: XIBCellViewModel) {
label.text = "\(model.name)"
}
}
struct XIBCellViewModel: CellConvertible, CellModel {
let name: String
// MARK: CellConvertible
typealias Cell = XIBCell
}
DiffableCellKit 是建立在 CellKit
和 DifferenceKit
之上的扩展,它捕获你的数据源更改并自动更新/删除/插入你的 UITableView
/UICollectionView
cell。
DifferentiableCellModelDataSource
构建于与 CellModelDataSource
相同的基础之上,区别(这里没有双关语)在于它接受 DifferentiableCellModelSection
,并且当你更改其 sections
属性的内容时,数据源将向其 UITableView
/UICollectionView
发出动画更新。 DifferentiableCellModelDataSource
仍然是一个开放类,因此你可以继承它并覆盖它的方法和属性来满足你的需求。
let datasource = DifferentiableCellModelDataSource(self.tableView, sections: [
DifferentiableCellModelSection(arrayLiteral:
PrototypeCellViewModel(domainIdentifier: 1, name: "Prototype")
),
DifferentiableCellModelSection(arrayLiteral:
CodeCellViewModel(domainIdentifier: 2, name: "Code")
),
DifferentiableCellModelSection(arrayLiteral:
XIBCellViewModel(domainIdentifier: 3, name: "XIB")
)
])
就像 CellModel
一样,DifferentiableCellModel
是你的 cell 模型的协议。 DifferentiableCellModel
提供了一个新的 domainIdentifier
属性和一个 hasEqualContent(with:)
方法,它们为 DiffableCellKit
提供了足够的信息来识别更改并发出 UITableView
/UICollectionView
更新。
当你的 cell 模型符合 Equatable
协议时,DiffableCellKit
会提供一个 Equatable
扩展,因此你无需实现 hasEqualContent(with:)
方法。 DifferentiableCellModel 仍然可以与 CellConvertible
协议结合使用。
class XIBCell: UITableViewCell, CellConfigurable {
@IBOutlet private weak var label: UILabel!
func configure(with model: XIBCellViewModel) {
label.text = "\(model.name)"
}
}
struct XIBCellViewModel: CellConvertible, DifferentiableCellModel, Equatable {
let name: String
// MARK: DifferentiableCellModel
var domainIdentifier: Int
// MARK: CellConvertible
typealias Cell = XIBCell
}
class XIBCell: UITableViewCell, CellConfigurable {
@IBOutlet private weak var label: UILabel!
func configure(with model: XIBCellViewModel) {
label.text = "\(model.name)"
}
}
struct XIBCellViewModel: CellConvertible, CellModel {
let name: String
// MARK: CellConvertible
typealias Cell = XIBCell
}
class PrototypeCell: UITableViewCell, CellConfigurable {
@IBOutlet private weak var label: UILabel!
func configure(with model: PrototypeCellViewModel) {
label.text = "\(model.name)"
}
}
struct PrototypeCellViewModel: CellConvertible, CellModel {
let name: String
// MARK: CellConvertible
typealias Cell = PrototypeCell
let usesNib: Bool = false
let registersLazily: Bool = false
}
class CodeCell: UITableViewCell, CellConfigurable {
let label: UILabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
topAnchor.constraint(equalTo: label.topAnchor, constant: -16),
bottomAnchor.constraint(equalTo: label.bottomAnchor, constant: 16),
leftAnchor.constraint(equalTo: label.leftAnchor, constant: -16),
heightAnchor.constraint(equalToConstant: 64)
])
}
func configure(with model: CodeCellViewModel) {
label.text = "\(model.name)"
}
}
struct CodeCellViewModel: CellConvertible, CellModel {
let name: String
// MARK: CellConvertible
typealias Cell = CodeCell
let usesNib: Bool = false
let cellHeight: Double = 64
}
当前的维护者和主要贡献者是 Matěj Kašpar Jirásek, matej.jirasek@futured.app。
我们要感谢其他贡献者,即
CellKit 在 MIT 许可证下可用。 有关更多信息,请参见LICENSE。