NSCollectionView sizeForItemAt всегда возвращает исключение при попытке ссылки на элемент в его коллекции

Контекст -

Я работаю над приложением строки меню MacOS, которое отображает коллекцию элементов. Элементы существуют в виде коллекции и содержат текстовое поле.

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

Я считаю, что лучший способ сделать это в sizeForItemAt метод, но я не могу сослаться на ячейку и ее текстовое поле, чтобы вычислить и вернуть ее высоту. Всякий раз, когда я пытаюсь получить элемент collectiomView на этом этапе, приложение вылетает с [General] *** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0] исключение.

Мой код -

Мой viewDidLoad, где я "настраиваю" свой CollectionView

override func viewDidLoad() {
    super.viewDidLoad()

    configureCollectionView()
    ....
}

private func configureCollectionView() {
    let flowLayout = NSCollectionViewFlowLayout()

    flowLayout.itemSize.width = self.view.frame.width
    flowLayout.minimumLineSpacing = 8
    thoughtsCollectionView.collectionViewLayout = flowLayout
    view.wantsLayer = true
}

Это где я пытаюсь установить высоту динамически (и где она падает)

func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {

    guard collectionView.item(at: indexPath) != nil else { // <-- CRASHES HERE
        return NSSize(width: self.view.frame.width, height: 50)
    }

    return self.collectionView.item(at: indexPath)?.textField?.frame.height
}

Вот как я добавляю элементы в collectionView

func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {

    let item = collectionView.makeItem(withIdentifier: "CollectionViewItem", for: indexPath as IndexPath)
    guard let collectionViewItem = item as? CollectionViewItem else {return item}

    (item as! CollectionViewItem).textField?.stringValue = "Some Text"

    (item as! CollectionViewItem).delegate = self

    return item
}

Так что странно для меня, это то, что в моем collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) Я должен успешно получить товар, выполнив

func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {

    guard let indexPath = indexPaths.first else {
        return
    }

    guard collectionView.item(at: indexPath) != nil else {
        return
    }

    let item = collectionView.item(at: indexPath) as! CollectionViewItem // <--- This gets me an item fine

Так что я не уверен, почему я борюсь с sizeForItemAt, У меня такое чувство, потому что элементы еще не существуют (и создаются, когда представление начинает их отображать), но я не знаю, как правильно подойти к этому динамическому размеру.

0 ответов

Я столкнулся с той же проблемой. Читая документы, я обнаружил, что Apple намеревается позволить нам использоватьNSCollectionViewLayout вместо элемента.

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

Например, если у вас есть одно изображение, одна метка изменяемого размера и одна метка фиксированного размера. нравится: Изображение | Mutable Label | этикетка

Вы можете восстановить изменяемую метку следующим образом.

func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {

    let imageViewWidth:CGFloat = 20 + 64 + 20
    let account = self.dataObject[indexPath]
    let defaultLabelWidth:CGFloat = {
        if account.isDefault {
            let defaultLabel = NSTextField(labelWithString: NSLocalizedString("Default", comment: ""))
            defaultLabel.font = NSFont.systemFont(ofSize: 16.0)
            defaultLabel.sizeToFit()

            return 20 + defaultLabel.bounds.width + 20
        }

        return 0 + 0 + 20
    }()

    let nameLabelWidth:CGFloat = {
        let label = NSTextField(labelWithString: account.name)
        label.font = NSFont.systemFont(ofSize: 16.0)
        label.sizeToFit()

        return label.bounds.width
    }()

    return NSSize(width: imageViewWidth + nameLabelWidth + defaultLabelWidth, height: 80)
}
Другие вопросы по тегам