转载

自定义UICollectionViewLayout 实现瀑布流

今天研究了一下自定义UICollectionViewLayout。 看了看 官方文档 ,要自定义UICollectionViewLayout,需要创建一个UICollectionViewLayout的子类。同时,可以通过一下3个方法传递布局信息、contentSize、cells的信息等。

一、继承UICollectionViewLayout,重写以下方法

1.通过prepareLayout方法来计算预先计算需要提供的布局信息。

2.通过collectionViewContentSize方法来返回contentSize

3.通过layoutAttributesForElementsInRect: 方法来返回每个cell的信息

自定义UICollectionViewLayout 实现瀑布流

二、创建UICollectionViewLayoutAttributes,创建的方法有一下三种

1.layoutAttributesForCellWithIndexPath:

2.layoutAttributesForSupplementaryViewOfKind:withIndexPath:

3.layoutAttributesForDecorationViewOfKind:withIndexPath:

其中,layoutAttributesForCellWithIndexPath:方法创建cell的属性,layoutAttributesForSupplementaryViewOfKind:withIndexPath:创建补充视图的属性,如header、footer,layoutAttributesForDecorationViewOfKind:withIndexPath:创建修饰视图的属性

基础知识介绍完了,接下讲具体示例 创建一个UICollectionViewLayout的子类WKFlowLayout,

 @interface WKFlowLayout : UICollectionViewLayout  @property (nonatomic, strong) NSMutableDictionary *layoutInformation; @property (nonatomic) NSInteger maxNumCols;  @end  static NSUInteger CellWidth = 100;   static CGFloat ContentHeight;  @implementation WKFlowLayout {     NSMutableArray *_yOffsets;//存储各列的当前offest } 

接下来在prepareLayout预先计算布局信息

 - (void)prepareLayout {     _maxNumCols = 2;//设置为两列      _yOffsets = [NSMutableArray arrayWithCapacity:_maxNumCols];     for (int i = 0; i < _maxNumCols; i++) {         [_yOffsets addObject:@0];     }      //初始化cell的宽度     CellWidth = self.collectionView.bounds.size.width / _maxNumCols;      //事先创建好UICollectionViewLayoutAttributes     _layoutInformation = [NSMutableDictionary dictionary];      NSIndexPath *indexPath;     NSInteger numSections = [self.collectionView numberOfSections];     for(NSInteger section = 0; section < numSections; section++){         NSInteger numItems = [self.collectionView numberOfItemsInSection:section];         for(NSInteger item = 0; item < numItems; item++){             indexPath = [NSIndexPath indexPathForItem:item inSection:section];             UICollectionViewLayoutAttributes *attributes =             [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];              NSInteger col = indexPath.item % _maxNumCols;              WKFlowLayoutDataSource *ds = self.collectionView.dataSource;              NSNumber *height = ds.dataSource[indexPath.row];             attributes.frame = CGRectMake(col * CellWidth, [_yOffsets[col] floatValue], CellWidth, [height floatValue]);             CGFloat yOffset;              yOffset = [_yOffsets[col] floatValue] + [height floatValue];             NSLog(@"yOffset:%f col:%ld", yOffset, (long)col);              _yOffsets[col] = @(yOffset);              [_layoutInformation setObject:attributes forKey:indexPath];             //计算滚动高度             ContentHeight = MAX(ContentHeight, CGRectGetMaxY(attributes.frame));         }     } } 

剩下的代码

 - (CGSize)collectionViewContentSize {     CGFloat contentWidth = self.collectionView.bounds.size.width;      CGSize contentSize = CGSizeMake(contentWidth, ContentHeight);     return contentSize; }  - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {     NSMutableArray *myAttributes = [NSMutableArray arrayWithCapacity:self.layoutInformation.count];     for(NSString *key in self.layoutInformation.allKeys){         UICollectionViewLayoutAttributes *attributes = [self.layoutInformation objectForKey:key];              if(CGRectIntersectsRect(rect, attributes.frame)){                 [myAttributes addObject:attributes];          }     }     return myAttributes;  } 

以上就是主要的实现代码了,需要注意的是,在prepareLayout中预先算出所有的布局信息适用于cell个数小于1000,超过之后在耗时就过长了,用户体验不好,同时需要在- (BOOL)shouldInvalidateLayoutForBoundsChange:方法中返回NO,此方法表示不需要再滚动过程中不停的调用prepareLayout

 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {     return NO; } 

示例代码 再附上官方的 circleLayout

原文  http://www.cnblogs.com/pretty-guy/p/5132707.html
正文到此结束
Loading...