Липкий заголовок UICollectionViewCompositionalLayout дергается

Я пытаюсь использовать последнюю версию UICollectionViewCompositionalLayout для отображения данных с разбивкой на страницы с помощью UICollectionViewDiffableDataSource . Я хотел показать липкий заголовок над разделом, который всегда оставался бы наверху даже при загрузке данных следующей страницы из сети. Я заметил, что липкий заголовок не работает должным образом и вместо этого кажется дергающимся при загрузке данных в фоновом режиме и применив новый снимок.. Мне удалось воспроизвести эту проблему с помощью примера приложения, предоставленного Apple здесь

Вот код для воспроизведения проблемы:

func layout() -> UICollectionViewLayout {
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                         heightDimension: .fractionalHeight(1.0))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)

    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                          heightDimension: .absolute(44))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

    let section = NSCollectionLayoutSection(group: group)
    section.interGroupSpacing = 5
    section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)

    let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
        layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                          heightDimension: .estimated(44)),
        elementKind: sectionHeaderElementKind,
        alignment: .top)
    sectionHeader.pinToVisibleBounds = true
    sectionHeader.zIndex = 2
    section.boundarySupplementaryItems = [sectionHeader]

    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
}

Приведенный выше фрагмент предоставляет UICollectionViewCompositionalLayout с заголовком раздела, закрепленным на видимых границах вверху.

func setUpCollectionView() {
    let collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout())
    collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    collectionView.backgroundColor = .systemBackground
    collectionView.register(ListCell.self, forCellWithReuseIdentifier: ListCell.reuseIdentifier)
    collectionView.register(TitleSupplementaryView.self,
                forSupplementaryViewOfKind: sectionHeaderElementKind,
                withReuseIdentifier: TitleSupplementaryView.reuseIdentifier)
    self.view.addSubview(collectionView)
    collectionView.refreshControl = refreshControl
    self.collectionView = collectionView
}

В приведенном выше коде я добавляю представление коллекции для просмотра представления контроллеров.

func configureDataSource() {
    guard let collectionView = self.collectionView else {
        return
    }

    dataSource = UICollectionViewDiffableDataSource<String, Int>(collectionView: collectionView) {
        (collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in

        // Get a cell of the desired kind.
        guard let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: ListCell.reuseIdentifier,
            for: indexPath) as? ListCell else { fatalError("Cannot create new cell") }

        // Populate the cell with our item description.
        cell.label.text = "\(indexPath.section),\(indexPath.item)"

        if self.canLoadNextPage(indexpath: indexPath) {
            self.getNextPage()
        }

        // Return the cell.
        return cell
    }

    dataSource?.supplementaryViewProvider = {
        (collectionView: UICollectionView, kind: String, indexPath: IndexPath) -> UICollectionReusableView? in

        // Get a supplementary view of the desired kind.
        guard let headerFooter = collectionView.dequeueReusableSupplementaryView(
            ofKind: kind,
            withReuseIdentifier: TitleSupplementaryView.reuseIdentifier,
            for: indexPath) as? TitleSupplementaryView else { fatalError("Cannot create new header") }

        headerFooter.label.text = sectionHeader
        headerFooter.backgroundColor = .lightGray
        headerFooter.layer.borderColor = UIColor.black.cgColor
        headerFooter.layer.borderWidth = 1.0

        // Return the view.
        return headerFooter
    }

    var snapshot = NSDiffableDataSourceSnapshot<String, Int>()
    snapshot.appendSections([section])
    items = Array(currentOffset..<currentOffset + 2*itemsPerPage)
    currentOffset += 2*itemsPerPage

    snapshot.appendItems(items)

    serialQueue.async { [weak self] in
        self?.dataSource?.apply(snapshot, animatingDifferences: true)
    }
}

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

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

func canLoadNextPage(indexpath: IndexPath) -> Bool {
    guard (indexpath.item + 5) > currentOffset else {
        return false
    }

    return true
}

func getNextPage() {
    fetchQueue.asyncAfter(deadline: .now() + 0.5) {
        var snapshot = NSDiffableDataSourceSnapshot<String, Int>()
         snapshot.appendSections([section])
        self.items.append(contentsOf: Array(self.currentOffset..<self.currentOffset + itemsPerPage))
        snapshot.appendItems(self.items)
        self.currentOffset += itemsPerPage

        self.serialQueue.async { [weak self] in
            self?.dataSource?.apply(snapshot, animatingDifferences: true)
        }
    }
}

Аналогичное поведение наблюдается и с действиями "Потяните для обновления".

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

Ценю любую помощь..

0 ответов

Другие вопросы по тегам