我看过这个类似的问题:How to deal with empty items section in UICollectionView CompositionalLayout,但答案似乎是在快照中留下部分(我这样做了,但这留下了另一个问题,我描述稍后)或渲染一个非常小的部分。该解决方案似乎不是一个好的解决方案。
我有一个使用组合布局和可区分数据源的集合视图。集合视图有四个部分,但每个部分都是可选的,这意味着如果该部分的相应数据为空,则不应显示该部分。
代码
布局定义
我有一个部分提供程序,它使用sectionIndex
来配置每个部分的外观。我认为这很糟糕,因为如果我在快照中没有第三部分的数据,例如,那么通常应该在第四部分中的所有内容现在都会有一个 indexPath,这将导致它像第三部分一样布局。
每个部分都有不同的项目大小,有些是正交滚动部分。因此,如果使用第三节布局呈现第四节数据,那么它看起来会出错。
NSCollectionLayoutSection * _Nullable (^sectionProvider)(NSInteger, id<NSCollectionLayoutEnvironment> _Nonnull) = ^NSCollectionLayoutSection * _Nullable (NSInteger sectionIndex, id<NSCollectionLayoutEnvironment> _Nonnull layoutEnvironment) {
if (sectionIndex == 0) {
//configure and return a layout for the first section
} else if (sectionIndex == 1) {
//configure and return a layout for the second section
} else if (sectionIndex == 2) {
//configure and return a layout for the third section
} else if (sectionIndex == 3) {
//configure and return a layout for the fourth section
}
return nil;
};
UICollectionViewCompositionalLayoutConfiguration *configuration = [[UICollectionViewCompositionalLayoutConfiguration alloc] init];
configuration.interSectionSpacing = 10;
configuration.scrollDirection = UICollectionViewScrollDirectionVertical;
self->_collectionViewLayout = [[UICollectionViewCompositionalLayout alloc] initWithSectionProvider:sectionProvider configuration:configuration];
数据源定义
这是定义数据源的地方。每个部分使用不同的数据模型类,因此我根据数据模型类的类型而不是索引路径来决定使用哪种类型的单元格。
self->_dataSource = [[UICollectionViewDiffableDataSource alloc] initWithCollectionView:self.collectionView cellProvider:^UICollectionViewCell * _Nullable(UICollectionView * _Nonnull collectionView, NSIndexPath * _Nonnull indexPath, id _Nonnull item) {
if ([item isKindOfClass:[MyFirstSectionModel class]]) {
return [collectionView dequeueConfiguredReusableCellWithRegistration:firstSectionCellRegistration forIndexPath:indexPath item:item];
} else if ([item isKindOfClass:[MySecondSectionModel class]]) {
return [collectionView dequeueConfiguredReusableCellWithRegistration:secondSectionCellRegistration forIndexPath:indexPath item:item];
} else if ([item isKindOfClass:[MyThirdSectionModel class]]) {
return [collectionView dequeueConfiguredReusableCellWithRegistration:thirdSectionCellRegistration forIndexPath:indexPath item:item];
} else if ([item isKindOfClass:[MyFourthSectionModel class]]) {
return [collectionView dequeueConfiguredReusableCellWithRegistration:fourthSectionCellRegistration forIndexPath:indexPath item:item];
}
return nil;
}];
快照构建
这里是包含每个部分(如果有数据)或排除(如果该部分为空)的位置。但是留下一个部分(例如,如果第三部分没有任何数据,那么它将被遗漏,但这将使第四部分的数据具有索引为 2 的索引路径,这将不适用于部分提供者。
如果我在快照中插入一个空部分,那仍然不起作用,因为其中一些部分有标题,所以如果它是一个有标题的部分,那么标题仍然会显示。但即使这些部分都没有标题,我认为它仍然会为该部分呈现一些额外的空白空间(但这可能是不正确的)。
- (void)reloadDataSourceAnimated:(BOOL)animated {
NSDiffableDataSourceSnapshot<CICustomerReviewsSectionIdentifierType, CICustomerReviewsItemIdentifierType> *snapshot = [[NSDiffableDataSourceSnapshot alloc] init];
if (self.firstSectionItems.count) {
[snapshot appendSectionsWithIdentifiers:@[MyFirstSectionIdentifier]];
[snapshot appendItemsWithIdentifiers:@[self.firstSectionItems] intoSectionWithIdentifier:MyFirstSectionIdentifier];
}
if (self.secondSectionItems.count) {
[snapshot appendSectionsWithIdentifiers:@[MySecondSectionIdentifier]];
[snapshot appendItemsWithIdentifiers:@[self.secondSectionItems] intoSectionWithIdentifier:MySecondSectionIdentifier];
}
if (self.thirdSectionItems.count) {
[snapshot appendSectionsWithIdentifiers:@[MyThirdSectionIdentifier]];
[snapshot appendItemsWithIdentifiers:@[self.thirdSectionItems] intoSectionWithIdentifier:MyThirdSectionIdentifier];
}
if (self.fourthSectionItems.count) {
[snapshot appendSectionsWithIdentifiers:@[MyFourthSectionIdentifier]];
[snapshot appendItemsWithIdentifiers:self.fourthSectionItems intoSectionWithIdentifier:MyFourthSectionIdentifier];
}
[self.dataSource applySnapshot:snapshot animatingDifferences:animated];
}
概括
所以问题是,如果我的一个或多个部分没有数据,那么当它们被排除在快照之外时,这将导致后续部分的数据呈现在错误的部分中(因为部分提供者配置了基于空部分之后的每个部分的索引和 indexPaths 不再是原始 indexPath)。
问题
- 有没有办法让这些部分是可选的,并且任何常规视图和补充视图都不会为“空”部分呈现?