FHDiffableViewControllers

Xcode Build Version License Tweet

基于 DiffableDataSource 的 UITableViewController 和 UICollectionViewController。

要求

安装

Swift 包管理器

将以下内容添加到你的 Package.swift 的依赖项中

.package(url: "https://github.com/FelixHerrmann/FHDiffableViewControllers.git", from: "x.x.x")

Xcode

按照此处所示,将包添加到你的项目中。

手动

下载 Sources 文件夹中的文件并将它们拖到你的项目中。

用法

如果你使用 Swift 包管理器,你必须使用 import FHDiffableViewControllers 将 FHDiffableViewControllers 导入到你的文件中。

现在你可以从 FHDiffableTableViewControllerFHDiffableCollectionViewController 继承你的视图控制器类。


但首先你需要一个 SectionIdentifierItemIdentifier,它们将被用于泛型类型。这两种类型都必须符合 Hashable

enum Section {
    case main, detail
}

struct Item: Hashable {
    var title: String
}

建议使 item 符合 Identifiable,因为如果数据源中存在重复项,应用程序会崩溃!


这些类可以这样被子类化

class TableViewController: FHDiffableTableViewController<Section, Item> {
    
    override var cellProvider: UITableViewDiffableDataSource<Section, Item>.CellProvider {
        return { tableView, indexPath, item in
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
            cell.textLabel?.text = item.title
            return cell
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        
        applySnapshot(animatingDifferences: false) {
            FHSection(.main) {
                Item(title: "First Item")
                Item(title: "Second Item")
            }
            FHSection(.detail) {
                Item(title: "Third Item")
            }
        }
    }
}

必须覆盖 cellProvider,因为默认实现会引发致命错误。在你第一次调用 applySnapshot(_:) 之前,不要忘记注册单元格!


单元格选择可以这样实现

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let item = dataSource.itemIdentifier(for: indexPath)
    /*do your actions with the selected item*/
}

自定义 Header 和 Footer 视图(仅限 collection view)

为了使用自定义 header 或 footer 视图,必须覆盖 supplementaryViewProvider 属性。

override var supplementaryViewProvider: UICollectionViewDiffableDataSource<Section, Item>.SupplementaryViewProvider? {
    return { collectionView, kind, indexPath in
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "customHeader", for: indexPath) as? CustomHeader
        switch self.dataSource.snapshot().sectionIdentifiers[indexPath.section] {
        case .main:
            headerView?.backgroundColor = .systemGreen
        case .detail:
            headerView?.backgroundColor = .systemPink
        }
        return headerView
    }
}

在你第一次调用 applySnapshot(_:) 之前,不要忘记注册 supplementary 视图!

collectionView.register(CustomHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "customHeader")

自定义数据源

如果你想更改标题创建的行为,或者你想使用 section index titles 和其他功能,你必须对相应的数据源进行子类化。 对于 table view,它可能看起来像这样

class CustomDataSource: UITableViewDiffableDataSource<Section, Item> {
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch snapshot().sectionIdentifiers[section] {
        case .main:
            return "Main"
        case .detail:
            return "Detail"
        }
    }
}

对 collection view 使用 UICollectionViewDiffableDataSource

为了在我们的视图控制器中使用它,我们必须创建一个它的 lazy var 并用它覆盖 dataSource 属性。

lazy var customDataSource = CustomDataSource(tableView: tableView, cellProvider: cellProvider)

override var dataSource: UITableViewDiffableDataSource<Section, Item> {
    return customDataSource
}

自定义 applySnapshot(_:)

你不必强制使用 applySnapshot(_:)FHDiffableDataSourceSection 数组结合来将快照应用到你的 dataSource。 你可以覆盖 applySnapshot(_:) 来更改它的行为,创建你自己的 applySnapshot() 方法,或者手动执行,如下所示

var snapshot = FHSnapshot()
snapshot.appendSections([.main, .detail])
snapshot.appendItems([Item(title: "Main Item")], toSection: .main)
snapshot.appendItems([Item(title: "Detail Item")], toSection: .detail)
dataSource.apply(snapshot, animatingDifferences: true, completion: nil)

Section & Item 构建器

除了传统的数组方式,还有 Section 和 Item 创建的结果构建器。

数组
applySnapshot([
    FHSection(.main, items: [
        Item(title: "First Item"),
        Item(title: "Second Item"),
    ]),
    FHSection(.detail, items: [
        Item(title: "Third Item"),
    ]),
])
结果构建器
applySnapshot {
    FHSection(.main) {
        Item(title: "First Item")
        Item(title: "Second Item")
    }
    FHSection(.detail) {
        Item(title: "Third Item")
    }
}

许可证

FHConstraints 在 MIT 许可证下可用。 有关更多信息,请参阅 LICENSE 文件。