【发布时间】:2017-01-01 17:24:54
【问题描述】:
我想使用UICollectionViewController 构建一个iOS 应用程序,每行始终具有相同数量的单元格。因为我不希望我的UICollectionViewController 处理太多事情,所以我重构了我的代码并实现了有趣的事情,比如protocol associatedtype 和泛型类型。现在,我的应用由 4 个不同的 .swift 文件组成。
1。 CustomFlowLayout.swift
CustomFlowLayout 是UICollectionViewFlowLayout 的一个简单子类,借助便利的初始化程序,它允许我们通过依赖注入设置其minimumInteritemSpacing、minimumLineSpacing 和sectionInset 属性。
import UIKit
class CustomFlowLayout: UICollectionViewFlowLayout {
convenience init(minimumInteritemSpacing: CGFloat = 0,
minimumLineSpacing: CGFloat = 0,
sectionInset: UIEdgeInsets = .zero) {
self.init()
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
}
override init() {
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
2。 ColumnDataSource.swift
ColumnDataSource 是NSObject 的子类,符合UICollectionViewDataSource、UICollectionViewDelegate 和UICollectionViewDelegateFlowLayout。它实现了collectionView(_:layout:sizeForItemAt:),以便每行显示正确的UICollectionViewCells 数量。另请注意,ColumnDataSource 是一个泛型类,需要我们在初始化时向其传递类型参数。
import UIKit
class ColumnDataSource<FlowLayoutType: UICollectionViewFlowLayout>: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellsPerRow: Int
init(cellsPerRow: Int) {
self.cellsPerRow = cellsPerRow
super.init()
}
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
}
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let flowLayout = collectionView.collectionViewLayout as! FlowLayoutType
let marginsAndInsets = flowLayout.sectionInset.left + flowLayout.sectionInset.right + flowLayout.minimumInteritemSpacing * (CGFloat(cellsPerRow) - 1)
let itemWidth = (collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)
return CGSize(width: itemWidth, height: itemWidth)
}
}
3。 ColumnFlowLayoutable.swift
ColumnFlowLayoutable 协议的目的是确保任何符合它的类都具有columnDataSource 和customFlowLayout 属性,其中columnDataSource 类型的类型参数与customFlowLayout 类型匹配。
import UIKit
protocol ColumnFlowLayoutable {
associatedtype FlowLayoutType: UICollectionViewFlowLayout
var columnDataSource: ColumnDataSource<FlowLayoutType> { get }
var customFlowLayout: FlowLayoutType { get }
}
4。 CollectionViewController.swift
CollectionViewController 是UICollectionViewController 的子类,符合ColumnFlowLayoutable 协议。它还实现了viewWillTransition(to:with:),以处理容器大小的变化。
import UIKit
class CollectionViewController: UICollectionViewController, ColumnFlowLayoutable {
let columnDataSource = ColumnDataSource<CustomFlowLayout>(cellsPerRow: 2)
let customFlowLayout = {
CustomFlowLayout(minimumInteritemSpacing: $0, minimumLineSpacing: $0, sectionInset: UIEdgeInsets(top: $0, left: $0, bottom: $0, right: $0))
}(10)
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.collectionViewLayout = customFlowLayout
collectionView?.dataSource = columnDataSource
collectionView?.delegate = columnDataSource
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
collectionView?.collectionViewLayout.invalidateLayout()
}
}
完整的项目可以在这个 Github 仓库找到:CollectionViewColumnsProtocol。
此代码运行良好。我可以将它与CustomFlowLayout 的子类一起使用,它仍然有效。 但是,我不能将它与 ColumnDataSource 的子类一起使用。
如果我尝试在CollectionViewController 中使用ColumnDataSource 的子类(例如class SubColumnDataSource: ColumnDataSource<CustomFlowLayout>)来构建项目,Xcode 会抛出以下构建时错误消息:
类型“CollectionViewController”不符合协议“ColumnFlowLayoutable”
为了让CollectionViewController 能够与ColumnDataSource 的子类一起工作,我必须对ColumnFlowLayoutable 协议进行哪些更改?
【问题讨论】:
标签: ios swift generics uicollectionview protocols