CellKit icon

CellKit

Cocoapods Cocoapods platforms License

CellKit 是一个 Swift 包,它简化了在 UITableView 和 UICollectionView 中使用 cell 的工作流程。无需再注册 cell 类或 XIB,无需再出队 cell 并设置其视图模型。CellKit 会处理这一切。

安装

Swift Package

将以下行添加到你的 Swift Package 依赖项中,或者在 Xcode 中,转到File -> Swift Packages -> Add Package Dependency,然后输入此仓库的 URL 地址。

.package(url: "https://github.com/futuredapp/CellKit", from: "0.8.1")

(可选)你可以添加 DiffableCellKit

CocoaPods

将以下行添加到你的 Podfile 中,然后运行 pod install

pod 'CellKit', '~> 0.8'

(可选)你可以添加 DiffableCellKit 子规范

pod 'CellKit', '~> 0.8', subspecs: ['Diffable']

用法

CellKit 提供了一个数据源和一个 section 模型,你可以用你的 cell、header 和 footer 模型来填充它们。 你需要做的就是定义你的 cell 视图和你的 cell 模型,并使其遵循 CellConvertible 和 CellConfigurable 协议,CellKit 将处理其余的事情。

1. 设置数据源

CellKit 提供了 CellModelDataSourceGenericCellModelSection,它们定义了你的 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

2. 创建你的 cell 和 CellModel

CellKit 支持各种 cell 声明方式,包括 .xib 文件,UITableView 界面构建器原型 cell 和完全用代码编写的 cell。
请注意,你的 .xib 文件、Cell 子类和 Cell 标识符必须具有相同的名称。 可以不使用相同的标识符,但不建议这样做。
专业提示:你可以使用我们的 自定义模板只需点击几下即可生成带有 CellKit 协议的 Cell。

3. 遵循 CellKit 协议

为了使你的 cell 和 cell 视图模型能够与 CellKit 一起工作,它们必须遵循以下协议

CellConfigurable

这是你的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
    }
}

CellModel

你的 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 指示是否应隐藏分隔符

CellConvertible

此协议使用关联类型扩展了 CellModel,因此可以根据类型的名称提供默认的 cellClassreuseIdentifier 值。
当你在 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

DiffableCellKit 是建立在 CellKitDifferenceKit 之上的扩展,它捕获你的数据源更改并自动更新/删除/插入你的 UITableView/UICollectionView cell。

DifferentiableCellModelDataSource

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")
    )
])

DifferentiableCellModel

就像 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
}

CellKit 示例

XIB cell

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
}

Storyboard 原型 cell

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
}

代码定义的 Cell

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