美文网首页
数据驱动之 UICollectionViewController

数据驱动之 UICollectionViewController

作者: 啧啧同学 | 来源:发表于2020-08-05 07:15 被阅读0次

用数据驱动的方式,创建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]?

相关文章

网友评论

      本文标题:数据驱动之 UICollectionViewController

      本文链接:https://www.haomeiwen.com/subject/ugdirktx.html