闲着没事,无意间看到掌上英雄联盟查看皮肤中CollectionView的效果,觉得很不错,趁着机会也学习下UICollectionViewFlowLayout的自定义,先看效果:
查找资料,发现苹果提供了2个关于Layout的demo,
Apple demo下载
这个基本上就是复制LineLayout的学习,在原来的基础上优化了一点。
首先创建一个继承与UICollectionViewFlowLayout的类,
我的.h
@interface GLCollectionViewFlowLayou : UICollectionViewFlowLayout
实现文件中主要有四个方法:
//可以在此方法中初始化你的layout
- (void)prepareLayout {
//必须调用super
[super prepareLayout];
}
//在这里改变布局 滑动时会时时调用此方法
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
}
//替换最终滑动的contentOffset, proposedContentOffset是预期滑动停止的位置
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
}
// 当collectionView bounds改变时,是否重新布局
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
苹果的LineLayout在滑到第一个和最后一个的时候,有点问题,不能更新到正确的位置。
在设置layout的时候设置UICollectionView的_collectionView.contentInset,设置如下:
CGFloat left = CGRectGetWidth(self.collectionView.frame) / 2 - flowLayout.itemSize.width / 2;
_collectionView.contentInset = UIEdgeInsetsMake(0, left, 0, left);
customLayout.m中,在targetContentOffsetForProposedContentOffset方法中处理第一个和最后一个的返回的contentOffset:
//替换希望的contentOffset
CGPoint actualPoint = CGPointMake(proposedContentOffset.x + minDistance, proposedContentOffset.y);
//处理第一个 和 最后一个的contentOffset
CGFloat minContentOffsetX = -floor(self.collectionView.contentInset.left);
CGFloat maxContentOffsetX = floor(self.collectionView.contentSize.width - CGRectGetWidth(self.collectionView.frame) + self.collectionView.contentInset.right);
actualPoint = actualPoint.x < minContentOffsetX ? CGPointMake(minContentOffsetX, actualPoint.y) : actualPoint;
actualPoint = actualPoint.x > maxContentOffsetX ? CGPointMake(maxContentOffsetX, actualPoint.y) : actualPoint;
return actualPoint;
这样就OK了,滑倒第一个和最后一个也可以正常的显示和滚动了。