Как предотвратить групповой фон в композиционном макете UICollectionView, чтобы скрыть элементы в этой группе?
Я использую композиционный макет UICollectionView, в котором я хочу иметь цвет фона и рамку контура позади группы элементов в разделе. Так что не фон для всего раздела, а только для группы. В разделе есть несколько групп, каждая со своим цветом фона. Я также хочу иметь возможность динамически устанавливать этот цвет фона и границы, т.е. цвет зависит от содержимого элемента. Вот почему я думаю, что не могу использовать предметы декора, но мне нужно использовать дополнительный вид.
Простой пример с одной группой с одним (синим) элементом на желтом фоне группы с красной рамкой выглядит так:
Кажется, что все нарисовано правильно, т.е. я вижу все свои элементы и все группы с их собственными цветами фона. Проблема в том, что хотя кажется, что фон группы находится за элементами, на самом деле он находится перед элементами, что я заметил, когда не получилdidSelectItemAt()
сообщения от делегата UICollectionView. (Я попытался убирая вид фона, а затем все работает, как ожидалось, и я сделал получатьdidSelectItemAt()
сообщения.) Я проверил иерархию представления отладки, и там ясно, что фон действительно находится перед всеми элементами, что, как мне кажется, является основной причиной моей проблемы:
(Иногда после удаления из очереди желтый фон ненадолго появляется перед синими элементами.) Итак, теперь я сбит с толку: как фоновое представление может быть наверху иерархии представлений и по-прежнему оставаться на заднем плане, в то время как в то же время didSelectItemAt()
не вызывается, когда я нажимаю на ячейку?
Ниже приведен код, в котором я сузил проблему до одного элемента (настраиваемый UICollectionViewCell) в одной группе с дополнительным представлением, которое является UICollectionReusableView
.
Я использую различные источники данных и определил псевдонимы для источника данных:
typealias DataSource = UICollectionViewDiffableDataSource<Section, Item>
private var dataSource: DataSource?
Сначала я регистрирую пользовательские UICollectionViewCell и UICollectionReusableView, а затем устанавливаю делегат UICollectionView для обработки сообщений didSelectItemAt():
let bundle = Bundle(for: LabelCollectionViewCell.self)
let nib = UINib(nibName: "LabelCollectionViewCell", bundle: bundle)
collectionView.register(nib, forCellWithReuseIdentifier: "LabelCollectionViewCell")
collectionView.register(BackgroundSupplementaryView.self, forSupplementaryViewOfKind: "Background", withReuseIdentifier: "BackgroundSupplementaryView")
collectionView.delegate = self
Затем я создаю источник данных следующим образом:
dataSource = DataSource(collectionView: collectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, item: Item) -> UICollectionViewCell? in
guard let cell: LabelCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "LabelCollectionViewCell", for: indexPath) as? LabelCollectionViewCell else {
fatalError("Could not dequeue cell")
}
cell.viewModel = LabelCollectionViewCell.ViewModel(text: item.labelText, backgroundColor: .blue)
return cell
}
Дополнительный вид устанавливается следующим образом:
dataSource?.supplementaryView = {
(collectionView: UICollectionView, kind: String, indexPath: IndexPath) -> UICollectionReusableView? in
if kind == "Background" {
guard let backgroundView: BackgroundSupplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: "Background", withReuseIdentifier: "BackgroundSupplementaryView", for: indexPath) as? BackgroundSupplementaryView else {
fatalError("Could not dequeue supplementary view")
}
backgroundView.backgroundColor = UIColor.yellow
backgroundView.borderColor = UIColor.red
backgroundView.layer.zPosition = -1
return backgroundView
}
return nil
}
Обратите внимание backgroundView.layer.zPosition = -1
, что иногда помогает предотвратить появление фона снова на переднем плане.
Элементы, группы и разделы построены следующим образом, и это также место, где я добавляю фон к группе (в этом примере есть только один из каждого):
collectionView.collectionViewLayout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
// Item
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)
// Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.3))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
// Group background
let backgroundSize = NSCollectionLayoutSize(widthDimension: groupSize.widthDimension, heightDimension: groupSize.heightDimension)
let background = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: backgroundSize, elementKind: "Background", alignment: .top)
group.supplementaryItems = [background]
// Section
return NSCollectionLayoutSection(group: group)
}
И, наконец, я обновляю пользовательский интерфейс, настраивая снимок:
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
let mainSection = Section(identifier: "MainSection", items: [Item]())
snapshot.appendSections([mainSection])
let item = Item(identifier: "I1", labelText: "L1")
snapshot.appendItems([item], toSection: mainSection)
self.dataSource?.apply(snapshot, animatingDifferences: true)
(Разделы и элементы - это просто обычные хешируемые структуры.)
Итак, есть ли кто-нибудь, кто может помочь? Почему я не получаюdidSelectItemAt()
сообщения, когда я нажимаю на элемент?? Заранее большое спасибо!