用数据驱动的方式,创建UICollectionViewController基类,方便的创建各种类型的collection布局页面;
同tableView类似,先定义好配置及对应collectionCell需要的刷新协议
//(identifier, cell config Infos, cell click action )
typealias YFCollectionItem = (String, CGSize ,Any?, ((IndexPath) -> ())?)
YFCollectionItem 的定义与YFCellItem相同,不再重复
//UICollectionViewController注册的cell均需要实现此协议
protocol YFCollectionViewCellProtocol {
func refreshUI(_ data: Any?)
}
构建CollcetionView的实例及布局
//Method
func setupSubviews() {
view.backgroundColor = .white
view.addSubview(collectionView)
collectionView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
/// collection的布局
/// 1.子类可以通过此方法来定制item的属性也可以通过实现UICollectionViewDelegateFlowLayout相关的代理方法来实现
/// 2.代理方法设置的值直接覆盖此方法直接设置layout的值
/// - Returns: UICollectionViewLayout
func makeCollectionViewLayout() -> UICollectionViewFlowLayout {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 60.0//最小行间距
layout.minimumInteritemSpacing = 60.0//每个小单元的间距
layout.sectionInset = UIEdgeInsets(top: collectionCellPadding, left: collectionCellPadding, bottom: 10.0, right: collectionCellPadding)
return layout
}
var listData: [[YFCollectionItem]] = []
@objc lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let view = UICollectionView.init(frame: .zero, collectionViewLayout: layout)
view.delegate = self
view.dataSource = self
view.allowsSelection = true
view.backgroundColor = .white
return view
}()
定义数据的配置及刷新方法
func reloadVisibleCells() {
let visibleItems = collectionView.indexPathsForVisibleItems
if visibleItems.count > 0 {
collectionView.reloadItems(at: visibleItems)
}
}
//Private
private func registerCollectionViewCells() {
for item in registerCells() {
if let cellClass = item.0 as? UICollectionViewCell.Type {
collectionView.register(cellClass, forCellWithReuseIdentifier: item.1)
}
if let cellNibName = item.0 as? String {
collectionView.register(UINib.init(nibName: cellNibName, bundle: nil), forCellWithReuseIdentifier: item.1)
}
}
}
func refreshUI() {
collectionView.collectionViewLayout = makeCollectionViewLayout()
listData = makeDisplayItems()
collectionView.reloadData()
}
对外提供配置方法
//MARK: for sub class override
///注册collection cell
///( 1.Any is Cell.type or String for nib name, 2.String is cellIdentifier)
func registerCells() -> [(Any, String)] {
return []
}
///构建展示数据model
func makeDisplayItems() -> [[YFCollectionItem]] {
return []
}
实现UICollectionViewDelegate, UICollectionViewDataSource两个协议:可读性,这里也使用extension小技巧
extension FCBaseCollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
//MARK: DataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return listData.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guard let sectionArray = sectionArrayAt(section) else {
return 0
}
return sectionArray.count
}
//MARK: Delegate
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let item = rowItemAt(indexPath) else {
return UICollectionViewCell()
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: item.0, for: indexPath)
//if cell confirm YFCollectionViewCellProtocol
if let collectionCell = cell as? YFCollectionViewCellProtocol {
collectionCell.refreshUI(item.2)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let item = rowItemAt(indexPath) else {
return
}
item.3?(indexPath)
}
}
//MARK: UICollectionViewDelegateFlowLayout
extension YFBaseCollectionViewController: UICollectionViewDelegateFlowLayout {
//基类默认参数,子类可以通过override来自定义
/*
1.通过YFCollectionItem传入size来定制item的大小
2.此代理方法用来设置item的大小, 如果设置了cellectionView的layout.estimatedItemSize属性,此方法将失效
3.实现此代理方法后,覆盖cellectionView的layout.itemSize值(此代理方法与直接设置layout.itemSize属性相同)
*/
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
guard let item = rowItemAt(indexPath) else {
return .zero
}
return item.1
}
}
调用的例子:
class FCTestCollectionViewController: YFBaseCollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
addObservers()
title = "collection测试".userLocal()
refreshUI()
}
override func makeCollectionViewLayout() -> UICollectionViewFlowLayout {
let layout = LeftAlignedCollectionViewFlowLayout()
layout.minimumLineSpacing = 0.0
layout.minimumInteritemSpacing = 0.0
layout.sectionInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 8.0, right: 0.0)
return layout
}
override func registerCells() -> [(Any, String)] {
return [(YFUserServiceCollectionCell.self, kYFUserServiceCollectionCell),
(YFUserSectionTitleCollectionViewCell.self, kYFUserSectionTitleCollectionViewCell),
(YFUserSectionFotterCollectionViewCell.self, kYFUserSectionFotterCollectionViewCell)]
}
override func makeDisplayItems() -> [[YFCollectionItem]] {
var items = [[YFCollectionItem]]()
guard let groups = self.groups else { return items }
groups.forEach({ (group) in
let title = YFCollectionItem(kYFUserSectionTitleCollectionViewCell, CGSize(width: UIScreen.main.bounds.size.width, height: 44.0), group.currentName(), nil)
let services = serviceItemsFormGroup(group)
var section = [YFCollectionItem]()
section.append(title)
section.append(contentsOf: services)
let surplus: Int = services.count % YFUserFlowBlockListCellVM.columnCount
// 当一行里面有空出来的地方补充白色
if surplus != 0, let itemWidth = services.first?.1.width, itemWidth != 0 {
let emptyItem = YFCollectionItem(kYFUserSectionFotterCollectionViewCell, CGSize(width: UIScreen.main.bounds.size.width - (CGFloat(surplus) * itemWidth), height: YFUserFlowBlockListCellVM.entryItemHeight), UIColor.white, nil)
section.append(emptyItem)
} else {
/* do nothing */
}
items.append(section)
})
return items
}
}
// 后台数据
var groups: [YFUserEntryGroup]?
网友评论