我的 UICollectionView 有一个组合布局。这是创建布局的代码。
func createLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout { [weak self] section, _ -> NSCollectionLayoutSection? in
guard
let self = self,
let sections = self.viewModel?.sections,
let sectionData = sections[safe: section] else { return nil }
switch sectionData {
case .firstSection:
return self.createFirstSectionSection()
case .secondSection:
return self.createSecondSection()
case .buttons(_, let topSpacing):
return self.createButtonsSection(topSpacing: topSpacing)
}
}
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(108))
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize,
elementKind: "header",
alignment: .top)
let config = UICollectionViewCompositionalLayoutConfiguration()
config.boundarySupplementaryItems = [header]
config.scrollDirection = .vertical
config.interSectionSpacing = 0
layout.configuration = config
return layout
}
func createFirstSection() -> NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(144))
let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [borderItem])
let group = NSCollectionLayoutGroup.vertical(layoutSize: itemSize, subitems: [item])
group.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 60, bottom: 0, trailing: 20)
let layoutSection = NSCollectionLayoutSection(group: group)
return layoutSection
}
func createSecondSection() -> NSCollectionLayoutSection {
let borderItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
let borderItem = NSCollectionLayoutSupplementaryItem(layoutSize: borderItemSize, elementKind: "item-border-view", containerAnchor: NSCollectionLayoutAnchor(edges: .top))
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(58))
let item = NSCollectionLayoutItem(layoutSize: itemSize, supplementaryItems: [borderItem])
let group = NSCollectionLayoutGroup.vertical(layoutSize: itemSize, subitems: [item])
group.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: hasCheckboxes ? 20 : 60, bottom: 0, trailing: 20)
let layoutSection = NSCollectionLayoutSection(group: group)
return layoutSection
}
func createButtonsSection(topSpacing: CGFloat) -> NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(41))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let group = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: itemSize.widthDimension, heightDimension: itemSize.heightDimension), subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: topSpacing, leading: 60, bottom: 0, trailing: 20)
return section
}
我的模型如下所示:
enum Section {
case firstSection(items: [FirstSectionItem])
case secondSection(items: [SecondSectionItem])
case buttons(cellViewModel: ButtonsCellViewModel, topSpacing: CGFloat)
var items: [AnyHashable] {
switch self {
case .firstSection(let firstSectionItems):
return firstSectionItems
case .quotes(let secondSectionItems):
return secondSectionItems
case .buttons(let cellViewModel, _):
return [cellViewModel]
}
}
}
// MARK: - Hashable
extension Section: Hashable {
static func == (lhs: Section, rhs: Section) -> Bool {
switch (lhs, rhs) {
case (.firstSection(let leftItems), .firstSection(let rightItems)):
return leftItems == rightItems
case (.secondSection(let leftItems), .secondSection(let rightItems)):
return leftItems == rightItems
case (.buttons(let leftCellViewModel, let leftTopSpacing), .buttons(let rightCellViewModel, let rightTopSpacing)):
return true
default:
return false
}
}
func hash(into hasher: inout Hasher) {
switch self {
case .firstSection(let items):
hasher.combine(items)
case .secondSection(let items):
hasher.combine(items)
case .buttons(let cellViewModel, let topSpacing):
hasher.combine("Same") // I use this to make sure that there is no difference in the buttons section. What I try to accomplish is that the buttons section (section at the bottom) does not animate out of screen to reload it's UI.
}
}
}
数据模型要复杂得多,但为了这个问题,我删除了一些我认为在这里不相关的东西,只会造成混乱。
使用 DiffableDataSource 重新加载 collectionView 如下所示:
func refreshUI() {
guard let viewModel = viewModel else { return }
let newDataSource = WorkApprovalDataSource(sections: viewModel.sections)
var snapshot = NSDiffableDataSourceSnapshot<APIWorkApprovalSection, AnyHashable>()
newDataSource.sections.forEach {
snapshot.appendSections([$0])
snapshot.appendItems($0.items, toSection: $0)
}
dataSource?.apply(snapshot, animatingDifferences: true)
}
关键是,我想要屏幕上的 3 个部分:
- 第一部分:一些行/项目在彼此下方
- 第二部分:与第一部分类似,但行/项目是可选的
- 第三部分:按钮部分。此部分始终存在。它至少有一个按钮。此部分始终包含 1 个单元格:该单元格包含带有按钮的水平堆栈视图。但是,正如我所说,至少总是有 1 个按钮。通过选中/取消选中第 2 节中的行/项目,按钮部分中有一个额外的按钮。当没有选择行时——>没有额外的按钮。当检查额外的行时,按钮的标题会根据所选/检查的行数发生变化:例如-->“发送(5)”。当仅选中 4 行时,此标题需要更改为“发送 (4)”。如果未选择任何行,则应隐藏此按钮。
从一开始就重新加载这些部分,我就遇到了麻烦。它上下跳跃。检查第2节的行时,de按钮部分不可见,因为第2节的项目列表太大,例如第一次检查/选择一行,它会跳转。之后,如果按钮部分仍然不在屏幕上,选择和取消选择行没有问题,不会发生跳转。
但是:当我滚动到底部以使按钮部分可见,然后选择一行时,集合视图会滚动一点,以使按钮看不见。当我再次滚动视线中的按钮时,单元格中的数据看起来很好,因此重新加载“正确”发生。我想要的是按钮部分不会滚动出屏幕来重新加载 UI。我通过使 Hashable 协议始终对相同的文本进行哈希处理来处理这个问题,所以没有区别,对吧?按钮标题的变化及其可见性,我通过按钮的 cellViewModel 处理。所以这工作得很好。但是按钮一直滚动到看不见的地方以重新加载。而且我不知道是什么原因造成的。
我真的需要装饰物品和东西的组合布局,所以我不能放弃这个。
提前感谢您查看并发布一些建议/修复。