注意:本文的 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
等等。