注意:本文的 UICollectionView 自定义是采用继承 UICollectionViewLayout 类的方式来自定义布局,而非系统默认使用 UICollectionViewFlowLayout 类来修改参数的方式。
- (void)prepareLayout;
- (CGSize)collectionViewContentSize;
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
prepareLayout : Item 的 position 和 CollectionView 的 size 。并且将其缓存下来,这种做法可以提升滚动流畅性。 [super prepareLayout] 。 collectionViewContentSize : CollectionView 的可拖动范围 ContentSize 。 ContentSize 而不是 Size 。 layoutAttributesForElementsInRect: : UICollectionViewLayoutAttributes 对象。 UICollectionViewLayoutAttributes 对象决定了 cell 的排布方式( frame 等)。 CollectionView , ContentSize 是 (320, 1000) , size 是 (320, 400) ,这时候如果滑到了 (0, 544, 320, 400) 。那么在这个区域有几个Cell,每个Cell的位置都是怎么样的?就得通过这个方法获知的。 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
shouldInvalidateLayoutForBoundsChange: : prepareLayout layoutAttributesForElementsInRect: targetContentOffsetForProposedContentOffset:withScrollingVelocity: : proposedContentOffset :默认情况下 CollectionView 停止滚动时最终的偏移量。 velocity :滚动速率,通过这个参数可以了解滚动的方向。 collectionView 停止滚动时最终的偏移量 contentOffset 向量速度 也就是 velocity 提供给我们来判定速度方向。当然如果是 拖动手势 而不是 拖甩手势 也就是没有加速度, velocity 直观的反应就是 0 。 在第一步 prepareLayout 方法执行的时候 预先计算 好每个 Item 在 UICollectionView 上的位置信息,然后保存在 UICollectionViewLayoutAttributes 对象里,再将其缓存。以便第二步和第三步计算。
第二步在 collectionViewContentSize 方法内利用第一步缓存的 Item 的位置信息计算 CollectionView 可拖动范围。
第三步在 layoutAttributesForElementsInRect: 方法内利用第一步缓存的 UICollectionViewLayoutAttributes 对象来计算 Item 是否在可视返回内,提取出可视的 Item 添加到 数组 对象并做返回。
通过以上三步我们缓存了每个 Item 的位置信息,再计算出 CollectionView 的可拖动范围,并且通过计算返回可视化区域需要的 UICollectionViewLayoutAttributes 对象数组。
最基本的 CollectionView 自定义布局就可以呈现了。
这一步比较随意,卡片悬停的位置算法需要根据 第一步 布局情况而定。
如果是需要高度优化悬停效果还需要用到 targetContentOffsetForProposedContentOffset:withScrollingVelocity: 方法里的 velocity 参数才做校正。
向量速度 和实时偏移量也就是 contentOffset ,再判断卡片的 中线位置 和 偏移量 的关系来决定是要悬停在上一张还是下一张卡。 中线 还是 边线 。 区域包含关系的内联函数 来获取得到可见或者某一区域的 Item 。 CGRectIntersectsRect 或者 CGRectContainsPoint 等等。