自定义UICollectionViewLayout 实现瀑布流

jopen 8年前

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

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

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

2.通过collectionViewContentSize方法来返回contentSize

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

二、创建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

</div>

来自: http://www.cnblogs.com/pretty-guy/p/5132707.html