Swift: Generi c Многоразовое представление коллекции при попытке добавить поддержку нескольких ячеек - PullRequest
0 голосов
/ 21 января 2020

Я следовал за несколькими машинами, чтобы создать collectionViewDataSource, и я очень доволен результатом:

        let dataSource = CollectionViewDataSourceProvider(items: domains, cell: EditDomainsCollectionViewCell.self) { indexPath, item, cell in
            cell.setup(with: item)
        }.registerCell(for: domainsCollectionView)

        self.datasource = dataSource
        domainsCollectionView.dataSource = datasource
        domainsCollectionView.delegate = datasource

Вот мой класс dataSourceProvider:

class CollectionViewDataSourceProvider<Item, Cell: UICollectionViewCell & NibLoadableView>: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    typealias CellConfigurator = (_ indexPath: IndexPath, _ item: Item, _ cell: Cell) -> ()
    typealias SizeConfigurator = (_ indexPath: IndexPath, _ item: Item) -> CGSize
    typealias WidthConfigurator = (_ section: Int) -> CGFloat
    typealias InsetConfigurator = (_ section: Int) -> UIEdgeInsets
    typealias SelectConfigurator = (_ indexPath: IndexPath, _ item: Item) -> ()

    private let items: [Item]
    private let cell: Cell.Type
    private let cellConfigurator: CellConfigurator
    private var sizeConfigurator: SizeConfigurator?
    private var minimumLineSpacingForSectionAtConfigurator: WidthConfigurator?
    private var minimumInteritemSpacingForSectionAt: WidthConfigurator?
    private var insetForSectionAt: InsetConfigurator?
    private var didSelectItemAt: SelectConfigurator?


    init(items: [Item], cell: Cell.Type, cellConfigurator: @escaping CellConfigurator) {
        self.items = items
        self.cell = cell
        self.cellConfigurator = cellConfigurator
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let model = items[indexPath.row]
        let cell = loadNIB()
        return sizeConfigurator?(indexPath, model) ?? cell.frame.size
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return minimumInteritemSpacingForSectionAt?(section) ?? (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing ?? 1
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return insetForSectionAt?(section) ?? (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        didSelectItemAt?(indexPath, items[indexPath.row])
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return minimumLineSpacingForSectionAtConfigurator?(section) ?? (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing ?? 1
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let model = items[indexPath.row]
        let cell: Cell = collectionView.dequeueReusableCell(forIndexPath: indexPath)

        cellConfigurator(indexPath, model, cell)
        return cell
    }

    private func loadNIB() -> Cell {
        return Bundle(for: Cell.self as AnyClass).loadNibNamed(String(describing: Cell.self), owner: nil, options: nil)![0] as! Cell
    }

}

extension CollectionViewDataSourceProvider {

    func registerCell(for collectionView: UICollectionView, flowLayout: UICollectionViewFlowLayout? = nil) -> CollectionViewDataSourceProvider {
        collectionView.register(cell)

        if let flowLayout = flowLayout {
            collectionView.setCollectionViewLayout(flowLayout, animated: true)
        }

        return self
    }

    func heightForRow(config: @escaping SizeConfigurator) -> CollectionViewDataSourceProvider {
        sizeConfigurator = config
        return self
    }

    func minimumLineSpacingForSectionAt(config: @escaping WidthConfigurator) -> CollectionViewDataSourceProvider {
        minimumLineSpacingForSectionAtConfigurator = config
        return self
    }

    func minimumInteritemSpacingForSectionAt(config: @escaping WidthConfigurator) -> CollectionViewDataSourceProvider {
        minimumInteritemSpacingForSectionAt = config
        return self
    }

    func insetForSectionAt(config: @escaping InsetConfigurator) -> CollectionViewDataSourceProvider {
        insetForSectionAt = config
        return self
    }

    func didSelectedAt(config: @escaping SelectConfigurator) -> CollectionViewDataSourceProvider {
        didSelectItemAt = config
        return self
    }

}

В конце концов, я пытаюсь реализовать возможность использования нескольких разных ячеек по протоколу, но я не могу адаптировать его с моим классом провайдера.

Вот шаблон, который я хочу создать для создания нескольких типов ячеек довольно просто:

enum CellType {
    case typeOne, typeTwo

   var identifier: String {
       switch self {
           case .typeOne:
               return NSStringFromClass(CellOne.self)
           case .typeTwo:
               return NSStringFromClass(CellTwo.self)
       }
   }
}

protocol CustomElement {
    var type: CellType { get }
}

class MyFirstObject: CustomElement {
    var type: CellType { .typeOne}
}

class MySecondObject: CustomElement {
    var type: CellType { .typeTwo}
}


protocol CellElement where Self: UICollectionViewCell & NibLoadableView {
    func configure(with object: CustomElement)
}

class CellOne: UICollectionViewCell, CellElement, NibLoadableView {
    func configure(with object: CustomElement) {
        guard let object = object as? MySecondObject else { return }
        //
    }
}

class CellTwo: UICollectionViewCell, CellElement, NibLoadableView {
    func configure(with object: CustomElement) {
        guard let object = object as? MyFirstObject else { return }
        //
    }
}

Протокол NibLoadableView исходит из этой сущности, чтобы легко сохранять ячейки https://gist.github.com/gonzalezreal/92507b53d2b1e267d49a

Я хочу, чтобы мой collectionViewDataSourceProvider мог получать в init массив ячеек UICollectionView, и если есть более чем одна ячейка, то реализуйте протокол logi c для нескольких ячеек. Но я не могу этого сделать.

Например, я пытаюсь установить протокол как общий параметр c в моем источнике данных, но он говорит мне, что протокол не наследуется от IUCollectionView.

У меня нет направления, как это сделать, спасибо за вашу помощь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...