Подтвердить что ты не робот

Заголовок раздела в UICollectionView с пользовательским UICollectionViewLayout

Я работаю над UICollectionView с пользовательским макетом. Через два дня я не могу понять, как добавить заголовок в UICollectionView. У меня очень простой контроллер просмотра (созданный в раскадровке с пользовательским макетом):

class ACollectionViewController: UICollectionViewController {

    enum Identifiers: String {
        case CellIdentifier = "Cell"
        case HeaderIdentifier = "Header"
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView.registerClass(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: Identifiers.HeaderIdentifier.rawValue)
    }

    // MARK: UICollectionViewDataSource
    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(Identifiers.CellIdentifier.rawValue, forIndexPath: indexPath) as Cell
        cell.backgroundColor = UIColor.redColor()
        return cell
    }

    override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
        println("ip = \(indexPath.item)")
        var supplementaryView = collectionView.dequeueReusableCellWithReuseIdentifier(Identifiers.HeaderIdentifier.rawValue, forIndexPath: indexPath) as UICollectionReusableView
        supplementaryView.backgroundColor = UIColor.blueColor()
        return supplementaryView
    }

И вот мой пользовательский макет:

class ALayout: UICollectionViewLayout {

    override func prepareLayout() {
        super.prepareLayout()
    }

    override func collectionViewContentSize() -> CGSize {
        return self.collectionView!.bounds.size
    }

    let itemWidth = 40
    override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
        var attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)

        let x: Float = Float(10) * Float(indexPath.item)
        let y: Float = Float(indexPath.item * itemWidth)
        attributes.frame = CGRect(x: CGFloat(x), y: CGFloat(y), width: CGFloat(itemWidth), height: CGFloat(itemWidth))

        return attributes
    }

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
        var attributes = [UICollectionViewLayoutAttributes]()

        let sectionsCount = self.collectionView!.dataSource!.numberOfSectionsInCollectionView!(self.collectionView!)
        for section in 0..<sectionsCount {
            /// add header
            attributes.append(self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: NSIndexPath(forItem: 0, inSection: section)))

            let itemsCount = self.collectionView!.numberOfItemsInSection(section)
            for item in 0..<itemsCount {
                let indexPath = NSIndexPath(forItem: item, inSection: section)
                attributes.append(self.layoutAttributesForItemAtIndexPath(indexPath))
            }
        }

        return attributes
    }

    override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
        var attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath)
        attributes.frame = CGRect(x: 0, y: 0, width: 320, height: 50)

        return attributes
    }
}

Проблема в том, что я не понимаю, как правильно добавить заголовок раздела, какой должен быть indexPath этого заголовка. В коде добавлен комментарий. Приложение сбой при запуске с ошибкой

2014-10-21 13:06:22.793 UICollectionViewLayout-Demo[3805:95924] *** Terminating app due to 
uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of 
kind: UICollectionElementKindCell with identifier Header - must register a nib or a class for 
the identifier or connect a prototype cell in a storyboard'

И я понимаю, это потому, что ячейка имеет тот же indexPath, что и заголовок раздела, который я пытаюсь добавить, но что должно быть indexPath заголовка? Или, может быть, я делаю это совершенно неправильно?

Спасибо заранее.

4b9b3361

Ответ 1

Ваш сбой возникает из-за того, что вы используете

var supplementaryView = collectionView.dequeueReusableCellWithReuseIdentifier(Identifiers.HeaderIdentifier.rawValue, forIndexPath: indexPath) as UICollectionReusableView

чтобы попытаться удалить верхний и нижний колонтитулы (в collectionView:viewForSupplementaryElementOfKind). Изменение его на

var supplementaryView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier:Identifiers.HeaderIdentifier.rawValue, forIndexPath: indexPath) as UICollectionReusableView

должен избавиться от сбоя, поэтому вы можете исследовать indexPath. Но в моем тесте indexPath всегда просто "0".

Ответ 2

Вместо var supplementaryView = collectionView.dequeueReusableCellWithReuseIdentifier(Identifiers.HeaderIdentifier.rawValue, forIndexPath: indexPath) as UICollectionReusableView

Должно быть

let supplementaryView = collectionView.dequeueReusableSupplementaryViewOfKind(kind withReuseIdentifier:Identifiers.HeaderIdentifier.rawValue, forIndexPath:indexPath)

Ответ 3

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

func dequeueReusableSupplementaryViewOfKind(_ elementKind: String,
                        withReuseIdentifier identifier: String,
                               forIndexPath indexPath: NSIndexPath!) -> AnyObject

вместо

 var supplementaryView = collectionView.dequeueReusableCellWithReuseIdentifier(Identifiers.HeaderIdentifier.rawValue, forIndexPath: indexPath) as UICollectionReusableView