Open jiangleligejiang opened 4 years ago
UICollectionView
布局layoutAttributesForElementsInRect
和layoutAttributesForItemAtIndexPath
之间的关系在自定义
UICollectionViewLayout
时,要注意若需要layoutAttributesForItemAtIndexPath
中实现对属性改变,则需要复写layoutAttributesForElementsInRect
方法,否则layoutAttributesForItemAtIndexPath
方法不会被调用。
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *attributesInRect = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes *cellAttributes in attributesInRect) {
[self modifyLayoutAttributes:cellAttributes];
}
return attributesInRect;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
[self modifyLayoutAttributes:attributes];
return attributes;
}
- (void)modifyLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes
{
// Adjust the standard properties size, center, transform etc.
// Or subclass UICollectionViewLayoutAttributes and add additional attributes.
// Note, that a subclass will require you to override copyWithZone and isEqual.
// And you'll need to tell your layout to use your subclass in +(Class)layoutAttributesClass
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CCCustomCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([CCCustomCell class]) forIndexPath:indexPath];
if (cell) {
cell.model = ...;
return cell;
}
return [[UICollectionViewCell alloc] init];
}
异常信息
Assertion failure in -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:notify:]
产生原因
cell为nil,所以返回了
UICollectionViewCell
实例,但UICollectionView
并没有注册UICollectionViewCell
,且不能直接通过alloc方法去创建UICollectionViewCell,必须使用dequeueReusableCellWithReuseIdentifier方法去获取,因此导致了异常出现。
结论
不推荐这种为了防止nil在最后返回
[[UICollectionViewCell alloc] init]
的方式,因为这样也会导致异常发生。若真的需要防止nil返回,可以考虑一下方式:
(UICollectionViewCell )collectionView:(UICollectionView )collectionView cellForItemAtIndexPath:(NSIndexPath )indexPath { CCCustomCell cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([CCCustomCell class]) forIndexPath:indexPath]; if (cell) { cell.model = ...; return cell; } return [self.collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([UICollectionViewCell class]) forIndexPath:indexPath]; }
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([UICollectionViewCell class])];
UICollectionView
的频繁刷新对于一些频繁变化的数据,比如监听说话的声音,根据声音的变化来显示动画,若我们的视图是
UICollectionViewCell
,那么要更新视图的话,通常会调用reloadData
方法。但这么做会导致其他cell
也会一起更新,而且更新的频率也比较高。为了避免这个问题,我们可以通过数据的引用传递,然后通过监听model
中对应的字段,从而监听到数据的变化。
- (void)addObservers {
if (_model) {
[_model addObserver:self forKeyPath:@"customField" options:NSKeyValueObservingOptionNew context:nil];
}
}
- (void)removeObservers {
if (_model) {
[_model removeObserver:self forKeyPath:@"customField" context:nil];
}
}
//监听`model`的`customField`字段的变化,从而做一些处理
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (object == _model && [keyPath isEqualToString:@"customField"]) {
[self dosomething];
}
}
- (void)setModel:(CustomModel *)model {
if (model && _model != model) {
[self removeObservers];
_model = model;
[self addObservers];
}
}
UICollectionView
的大小为zero
时,导致陷入[UICollectionViewData layoutAttributesForElementsInRect:]
死循环注意不要手动去设置UICollectionView
的width或height为0,否则就会出现死循环问题
zPosition
来设置UICollectionViewCell
的层级关系- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
.....
cell.layer.zPosition = indexPath.row;
return cell;
}
UICollectionView
的上下刷新效果UICollectionView
不足一屏的情况下,依旧存在上下刷新的效果