sizeForItemAtIndexPath在加载前被调用用于所有索引-我很确定我要么遇到UICollectionVie



我能够在一个非常简单的独立应用程序上重现这一点。

我有一个collectionView,我想让它循环/循环,这样元素就会一次又一次地重复(也就是说,当用户位于数组中的最后一个元素时,它会在之后再次显示第一个元素。如果他们位于第一个元素并向左滚动,它会再次显示最后一个元件(。所以这是一个永无止境的收藏View。

因此,作为一个简单的例子,让我们使用一周中的几天:

星期日、星期一、星期二、星期三。。星期六、星期日、星期一。。。。

为了实现这一点,我在numberOfItemsInSection中返回一个大数字(10000(,并在cellForItemAtIndexPath方法中使用indexPath.item%7来调整并获得正确的元素。使用%7,因为有7天。我的手机很简单,里面只有一个UILabel

这一切都很完美。

该问题与sizeForItemAtIndexPath有关。我希望单元格符合标签。由于实际大小只有7个变化,所以我在字典中预先缓存了7天的大小,并在sizeForItemAtIndexPath方法中返回正确的大小。

问题是(可能是由于collectionview的错误或苹果公司故意设计的错误(,sizeForItemAtIndexPath在collectionview出现之前会调用每个indexPath。因此,如果我想要循环collectionView逻辑,并且需要返回大数字(10000(,那么它就是为所有10000个索引调用sizeForItemAtIndexPath。因此,在collectionView出现之前会有几秒钟的延迟。如果我注释掉sizeForItemAtIndexPath,那么它会立即工作。所以这绝对是问题所在。我在sizeForItemAtIndexPath中放入了一个NSLog,它在加载之前记录了所有22222个调用。

我甚至定义了setEstimatedItemSize,它仍然为所有索引调用sizeForItemAtIndexPath

我可以通过返回较小的数字1000来减少延迟,但这肯定是一个糟糕的设计或错误。

TableView没有这个错误-你可以定义一百万行,它只在实际需要时调用heightForRow。所以我不知道为什么collectionView在显示之前需要为所有单元格调用它,尤其是如果setEstimatedItemSize也已经定义了。

这个错误的另一个副作用是,如果我返回一个更大的值,collectionView会抛出一个错误(50000会使它崩溃,22222也可以(。它打印的错误值太大:

This NSLayoutConstraint is being configured with a constant that exceeds internal limits.  A smaller value will be substituted, but this problem should be fixed. Break on BOOL _NSLayoutConstraintNumberExceedsLimit(void) to debug.  This will be logged only once.  This may break in the future.

TableView可以轻松处理巨大的值,因为它没有这个bug。

我也尝试过禁用prefetching,但没有效果。

你们怎么想?

相关代码:

#define kInfiniteCount 22222
#define kDayNameMargin 30
@interface ViewController (){
NSMutableDictionary *dictOfSizes;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
self.myCalendar = [NSCalendar currentCalendar];
[self.myCalendar setLocale:locale];
dictOfSizes = [NSMutableDictionary new];
for (int i=0; i<7; i++) {
WeekdayCollectionViewCell *sizingCell = [[NSBundle mainBundle] loadNibNamed:@"WeekdayCell" owner:self options:nil][0];
sizingCell.myLabel.text=[self.myCalendar weekdaySymbols][i];
[sizingCell layoutIfNeeded];
[dictOfSizes setObject:[NSValue valueWithCGSize:[sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]] forKey:sizingCell.myLabel.text];
}

self.myCollectionView.decelerationRate = UIScrollViewDecelerationRateFast;
[self.myCollectionView registerNib:[UINib nibWithNibName:@"WeekdayCell" bundle:nil] forCellWithReuseIdentifier:@"daycell"];
[(UICollectionViewFlowLayout*)self.myCollectionView.collectionViewLayout setEstimatedItemSize:CGSizeMake(200, self.myCollectionView.frame.size.height)];
[self.myCollectionView reloadData];

NSInteger middleGoTo = kInfiniteCount/2;
while (![[self.myCalendar weekdaySymbols][middleGoTo%7] isEqualToString:@"Monday"]) {
middleGoTo--;
}
[self.myCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:middleGoTo inSection:0] atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return kInfiniteCount;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
WeekdayCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"daycell" forIndexPath:indexPath];
cell.myLabel.text=[self.myCalendar weekdaySymbols][indexPath.item%7];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
NSLog(@"sizeForItemAtIndexPath: %ld",indexPath.item);
return [(NSValue*)[dictOfSizes objectForKey:[self.myCalendar weekdaySymbols][indexPath.item%7]] CGSizeValue];
}

编辑:

很少有人提到使用滚动视图而不是collectionview。

几乎在我研究循环滚动视图的所有地方,他们都建议为此使用collectionview,因为这要容易得多。我真正的需求有点复杂,这也需要我使用collectionview。

Scrollview要求您使用scrollViewDidSoll方法,并每次更改内容偏移量。此外,它一次将所有视图加载到内存中,因为它不像collectionview那样具有重用现有单元格的优势。这又是一次记忆冲击。

7个工作日是我使用的一个简单的例子。如果有人想显示大量数据(100(,那么滚动视图中的实现将非常糟糕,collectionview将出现此错误。

这是预期的行为,与UICollectionView没有太大关系,您使用的更多的是UICollectionViewFlowLayout

由于每个单元格大小不同,FlowLayout将分别请求每个单元格的大小,以计算CollectionView的总大小,这是正确处理滚动条所需的。

UITableView它稍微简单一点,因为它的布局要简单得多(只有高度很重要(——这就是为什么可以在那里使用estimatedSize的原因。

整个Core Layout Process在这里得到了很好的解释:

https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/CreatingCustomLayouts/CreatingCustomLayouts.html

为了克服这个问题,我建议使用您的自定义UICollectionViewLayout,移动您的缓存逻辑,并为CollectionViewLayout中的单元格重用大小,而不是ViewController中的单元格。

相关内容

  • 没有找到相关文章

最新更新