UICollectionViewFlowLayout子类:粘贴单元格在reloadData

时间:2015-05-07 01:41:18

标签: ios uicollectionview uicollectionviewlayout

我有以下UICollectionViewFlowLayout的子类:

@implementation MyFlowLayout

- (instancetype)init {
  self = [super init];
  self.stickyIndexPaths = [NSMutableArray array];
  return self;
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
  return YES;
}

- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
  CGRect collectionViewArea = CGRectMake(0.f, 0.f, self.collectionView.contentSize.width, self.collectionView.contentSize.height);
  NSArray *attributes = [super layoutAttributesForElementsInRect:collectionViewArea].copy;
  for (UICollectionViewLayoutAttributes *item in attributes) {
    [self makeStickyIfNeeded:item];
  }

  return attributes;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
  UICollectionViewLayoutAttributes *item = [super layoutAttributesForItemAtIndexPath:indexPath];
  [self makeStickyIfNeeded:item];
  return item;
}

- (void)makeStickyIfNeeded:(UICollectionViewLayoutAttributes*)item {
  BOOL indexPathIsSticky = [self.stickyIndexPaths indexOfObjectPassingTest:^BOOL(NSIndexPath *i, NSUInteger idx, BOOL *stop) {
    *stop = [i compare:item.indexPath] == NSOrderedSame;
    return *stop;
  }] != NSNotFound;
  if (indexPathIsSticky) {
    if (self.collectionView.contentOffset.y > item.frame.origin.y) {
      CGRect f = item.frame;
      f.origin.y = self.collectionView.contentOffset.y;
      item.frame = f;
      item.zIndex = 1.f;
    }
  }
  else {
    item.zIndex = 0.f;
  }
}

从上面可以看出,我可以添加单元格的indexPaths并使它们“粘贴”到顶部(假设是垂直流),而粘性单元格下面的任何其他单元格都会在下面滚动。我正在用一个粘性单元测试这个代码,在其下面,我有30个其他单元格(足以使内容偏移量大于粘性单元格的位置,这将导致它粘住其他单元格在它下面滚动)。到目前为止一切都很好。

但是我注意到了我的子类的两个副作用:

  1. 有时,当UICollectionView首次出现时,粘性单元格下方的单元格不会出现。如果我稍微滚动集合视图,那么它们就会出现。
  2. 如果我一直滚动到最后一个单元格(请记住这意味着此时某些单元格已在粘性单元格下方滚动),然后从我的数据源中删除一个单元格并执行-reloadData,而我得到正确的单元格数(比之前少一个),粘性标题不再可见。与第一种情况类似,如果我轻推集合视图,它会立即再次出现。
  3. 有什么想法吗?我认为这是一个新的contentOffset的问题,但似乎并非如此。

1 个答案:

答案 0 :(得分:0)

到目前为止,我发现的唯一解决方法是告诉收藏视图在我执行reloadData之后立即重新加载我发粘的项目。也就是说,考虑到我的示例代码中的布局对象有一个stickyIndexPaths数组,我可以这样做:

[self.collectionView reloadData];
[self.collectionView reloadItemsAtIndexPaths:self.layout.stickyIndexPaths];

(请注意,我在视图控制器中保留了对集合视图布局的引用。)

这样可以防止粘性细胞消失,但我仍然不知道它们为什么会消失。