自定義UICollectinviewFlowLayout,即實現瀑布流
來自: http://www.cnblogs.com/xueyao/p/5188321.html
如圖所示,通過實現不規則的網格分布,來顯示出不同的效果。因為集合視圖必須要指定布局還可以顯示,所以自定義布局就可以實現瀑布流的效果。
//創建布局對象 WaterFlowLayout *flowLayout = [[WaterFlowLayout alloc] init];flowLayout.delegate = self; flowLayout.numberOfColumn = 3; //創建集合視圖 UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];</pre>
因為系統自帶的布局有四個方法,分別實現了item大小,分區間隔,最小行間距,item之間的間隙大小
@protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate> @optional
- (CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
- (UIEdgeInsets)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
- (CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
(CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;</pre>
所以,自定義FlowLayout,并定義協議,以便定義這些方法。
@protocol WaterFlowLayoutDelegate <NSObject>
//關鍵方法,此方法的作用是返回每一個item的size大小 //數據中原始圖片大小
- (CGSize)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath; //分區間隔
- (UIEdgeInsets)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout insetForSectionAtIndex:(NSInteger)section; //得到 item之間的間隙大小
- (CGFloat)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section; //最小行間距
- (CGFloat)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
@end
@interface WaterFlowLayout : UICollectionViewLayout
//瀑布流一共多少列 @property (nonatomic, assign) NSUInteger numberOfColumn;
@property (nonatomic, assign) id<WaterFlowLayoutDelegate>delegate;</pre>
看圖可知,最小高的的item,將作為下一列item的起點。
@interface WaterFlowLayout ()//存放每一列的高度 @property (nonatomic, retain) NSMutableArray *columnHeightsArray;
//存放 每一個item的 屬性 包含 frame以及下標 @property (nonatomic, retain) NSMutableArray *attributesArray;
@end
@implementation WaterFlowLayout
//獲取最小高度的方法
- (CGFloat)minHeight
{
CGFloat min = 100000;
for (NSNumber *height in _columnHeightsArray) {
} return min; }CGFloat h = [height floatValue]; if (min > h) { min = h; }
//獲取最大值
- (CGFloat)maxHeight
{
CGFloat max = 0;
for (NSNumber *height in _columnHeightsArray) {
} return max; }CGFloat h = [height floatValue]; if (max < h) { max = h; }
//找到最小高的下標
- (NSUInteger)indexOfMinHeight
{
NSUInteger index = 0;
for (int i = 0; i < [_columnHeightsArray count]; i ++) {
} return index; }CGFloat height = [_columnHeightsArray[i] floatValue]; if (height == [self minHeight]) { index = i; return index; }
//重寫父類的布局方法
(void)prepareLayout { [super prepareLayout];
_attributesArray = [[NSMutableArray alloc] init];
_columnHeightsArray = [[NSMutableArray alloc] initWithCapacity:self.numberOfColumn];
//給列高數組里面的對象賦初值 for (int i = 0; i < self.numberOfColumn; i ++) {
[_columnHeightsArray addObject:@0.0];
}
CGFloat totalWidth = self.collectionView.frame.size.width;
//創建 每個item frame中的x、y CGFloat x = 0; CGFloat y = 0;
NSUInteger itemCount = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i < itemCount; i ++) {
//得到集合視圖中 列間隙的個數 NSUInteger numberOfSpace = self.numberOfColumn - 1; //代理對象執行代理方法,得到 item之間的間隙大小 CGFloat spaceWidth = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:0]; //求每列的寬度,也就是每個item的width CGFloat width = (totalWidth - spaceWidth * numberOfSpace) / self.numberOfColumn;
//獲取每一個itemSize的大小
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
//數據中原始圖片大小
CGSize imageSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
//通過 約分公式得到固定寬之后的高度是多少
CGFloat height = width * imageSize.height / imageSize.width;
UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//記錄每一個item的大小和位置
attribute.frame = CGRectMake(x, y, width, height);
//數組保存每個item的位置信息
[_attributesArray addObject:attribute];
NSLog(@"item = %d",i);
NSLog(@"x = %.2f y = %.2f width = %.2f height = %.2f",x,y,width,height);
//求列高最小的那一列的下標
NSUInteger minHeightIndex = [self indexOfMinHeight];
//求出最小列的高度
CGFloat minHeight = [_columnHeightsArray[minHeightIndex] floatValue];
//求出行高
CGFloat lineHeight = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:0];
//上一次總的列高 加上 行高 加上新加上的item的height,才是現在這一列的總高度
//minHeight為最小列現在的高度
//lineHeight為行間距
//height為新加的item的高
_columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height];
//重新算最小列高的下標
minHeightIndex = [self indexOfMinHeight];
//算下一次新加的item的x和y值
x = (spaceWidth + width) * minHeightIndex;
y = [self minHeight];
}
}
//重寫這個方法,可以返回集合視圖的總高度
- (CGSize)collectionViewContentSize { return CGSizeMake(self.collectionView.frame.size.width, [self maxHeight]); }
- (NSArray )layoutAttributesForElementsInRect:(CGRect)rect
{
return _attributesArray;
}</pre>
注意,最后一個方法的實現,即- (NSArray
)layoutAttributesForElementsInRect:(CGRect)rect,如果這個方法不寫,集合視圖是顯示不出來的,這個方法是次保存的每個item的信息重新告訴集合視圖,進行顯示。</p> </div>