I am experiencing an issue when rendering detachable sections in my assortment views. The setup is as follows:
The gathering view has two sections. The primary one incorporates just one cell, which when tapped triggers a snapshot replace that removes the sections from the gathering view. The second part incorporates a number of cells scrolling orthogonally.
The issue happens when scrolling the second part, after which tapping the one cell on the primary one.
The habits I count on is that the primary part can be eliminated, and the part would slide into the primary’s place in a clean animation.
What I am seeing is the orthogonally scrolling part flickering and leaping till the animation is full.
Listed below are some examples of what I would count on, and what occurs.
This is a code snippet able to drop on a Playground to check (Xcode 15.3, iOS 17). Please notice that it is simply an instance I attempted to distill from the true code, which is extra complicated.
import UIKit
import PlaygroundSupport
var onTap = {
removeSection()
}
// Rainbow coloured cells
closing class Cell: UICollectionViewCell {
override func prepareForReuse() {
contentView.backgroundColor = .clear
}
func configure(with coloration: UIColor) {
contentView.backgroundColor = coloration
}
}
// The cell that when tapped, triggers the part elimination (notice that choice is not being dealt with by didSelectItem.
closing class RemovableCell: UICollectionViewCell {
override init(body: CGRect) {
tremendous.init(body: body)
contentView.backgroundColor = .systemCyan
contentView.addGestureRecognizer(UITapGestureRecognizer(goal: self, motion: #selector(faucet)))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been applied")
}
@objc
func faucet() {
onTap()
}
}
// Registrations for the cells
let cellRegistration = UICollectionView.CellRegistration<Cell, Int> { cell, indexPath, _ in
let colours: [UIColor] = [.red, .orange, .yellow, .green, .blue]
cell.configure(with: colours[indexPath.item % colors.count])
}
let removableCellRegistration = UICollectionView.CellRegistration<RemovableCell, Int> { cell, indexPath, _ in }
let removableSection: NSCollectionLayoutSection = {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .estimated(120))
let merchandise = NSCollectionLayoutItem(layoutSize: itemSize)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: itemSize, subitems: [item])
let part = NSCollectionLayoutSection(group: group)
return part
}()
// Sections definitions
let orthogonallyScrollingSection: NSCollectionLayoutSection = {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(1))
let merchandise = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(
widthDimension: .estimated(100),
heightDimension: .fractionalHeight(0.2))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let part = NSCollectionLayoutSection(group: group)
part.orthogonalScrollingBehavior = .steady
return part
}()
// Assortment view building, please do not thoughts the mess.
var removeSectionAvailable = true
let format = UICollectionViewCompositionalLayout { part, _ in
if part == 0, removeSectionAvailable {
removableSection
} else {
orthogonallyScrollingSection
}
}
let body = CGRect(x: 0, y: 0, width: 300, top: 500)
let view = UICollectionView(body: body, collectionViewLayout: format)
let dataSource = UICollectionViewDiffableDataSource<Int, Int>(collectionView: view) { collectionView, indexPath, itemIdentifier in
if indexPath.part == 0, removeSectionAvailable {
return collectionView.dequeueConfiguredReusableCell(
utilizing: removableCellRegistration,
for: indexPath,
merchandise: itemIdentifier)
} else {
return collectionView.dequeueConfiguredReusableCell(
utilizing: cellRegistration,
for: indexPath,
merchandise: itemIdentifier
)
}
}
var snapshot = NSDiffableDataSourceSnapshot<Int, Int>()
snapshot.appendSections([0, 1])
snapshot.appendItems([0], toSection: 0)
snapshot.appendItems([1, 2, 3, 4, 5, 6], toSection: 1)
dataSource.apply(snapshot)
func removeSection() {
removeSectionAvailable = false
snapshot.deleteSections([0])
dataSource.apply(snapshot)
}
// Playground setup
PlaygroundPage.present.liveView = view
PlaygroundPage.present.needsIndefiniteExecution = true
All suggestions are appreciated!