最近上班比较无聊,闲来无事就在网上随便下项目看。
今天就来看看自定义瀑布流布局。
自定义瀑布流布局主要是新建一个继承自UICollectionViewFlowLayout的类,重点是实现该类中的一个方法:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 在这个方法里面,我们要算出每个item的文字和尺寸并返回给系统;
当该类被我们调用时系统会依次执行下列方法:
(1)- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds :当collectionView的显示范围发生改变的时候,是否需要重新刷新布局
一旦重新刷新布局,就会调用下面两个方法;
(2)- (void)prepareLayout :我们一般在这里执行一些初始化的操作
(3)- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 在这个方法里面,我们要算出每个item的文字和尺寸并赋值给每一个 UICollectionViewLayoutAttributes,然后返回给系统, 系统根据这个数组的布局属性展示collectionView,到这里自定义就搞定了。
当然,在这里我们也可以监听下面这个方法来控制congtenoffset:
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
下面现学现卖,自定义布局实现之前项目的一个功能:
之前的一个项目有一个需求:要求做成如下的分页效果
毫无疑问,这个功能肯定用UICollectionView来搞定它,但是难点就是这种不连续的分页效果,做起来比较麻烦。之前不知道重写UICollectionViewFlowLayout,于是在控制器里面直接监听- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity 这个方法,这算起来就十分蛋疼了,不行你可以试着玩玩。
但是!重点来了,如果通过继承UICollectionViewFlowLayout自定义一个布局,在这里面监听上面那个方法,那就爽歪歪了。我们可以轻松地拿到系统算好的布局,在这个布局的基础上做微调就可以了,核心代码就几句话:
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{
CGRect rect;
rect.origin.x = proposedContentOffset.x;
rect.origin.y = 0;
rect.size = self.collectionView.frame.size;
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGFloat collectionCenterX = self.collectionView.frame.size.width*0.5 + proposedContentOffset.x;
CGFloat minDelta = MAXFLOAT;
// 核心:判断collectionView的中心离哪个item更近就让那个item显示在中央
for (UICollectionViewLayoutAttributes *attrs in array) {
if (fabs(minDelta)>fabs(attrs.center.x-collectionCenterX)) {
minDelta = attrs.center.x-collectionCenterX;
}
}
proposedContentOffset.x+=minDelta;
return proposedContentOffset;
}
这里我们只是拿到系统算好的布局再做偏移,所以不必重新算布局。
如果要做想天猫商品展示不等高的界面,如图:
这种界面的思路就是布局固定两列,遍历商品数据逐个把商品加到列高比较小的那一列,算出各个item的布局属性(我们必须知道图片的宽高比),这种算起来就稍微麻烦一点了。