The new file inherits from uicollectionViewLayout. h and contains the following contents:

@class WaterFlowLayout; @protocol WaterFlowLayoutDelegate <NSObject> // use the delegate to get the height of each Cell - (CGFloat)waterFlow:(WaterFlowLayout *)layout heightForCellAtIndexPath:(NSIndexPath *)indexPath; @end @interface WaterFlowLayout : @property (nonatomic, weak) id <WaterFlowLayoutDelegate> delegate; @property (nonatomic, assign) NSInteger colum; @property (nonatomic, assign) UIEdgeInsets insetSpace; // Determine the distance between each cell @property (nonatomic, assign) NSInteger distance; @endCopy the code

.m implementation content is as follows:

@interface WaterFlowLayout () // Array of column heights @Property (nonatomic, strong) NSMutableArray *columHeightArr; @property (nonatomic, strong) NSMutableArray *cellFrameArr; Implementation WaterFlowLayout // implementation WaterFlowLayoutsetMethods - (void)setColum:(NSInteger)colum{
    if(_colum ! = colum) { _colum = colum; // Invalidate the previous layout information and rearrange [self invalidateLayout]; }} / / shortsetMethods - (void)setDistance:(NSInteger)distance{
    if(_distance ! = distance) { _distance = distance; [self invalidateLayout]; / / insetSpace}}setMethods - (void)setInsetSpace:(UIEdgeInsets)insetSpace{
    if(! UIEdgeInsetsEqualToEdgeInsets(_insetSpace, insetSpace)) { _insetSpace = insetSpace; [self invalidateLayout]; }} // Prepare the layout by computing the position of the item - (void)prepareLayout{// Instantiate the array of position and height information [self initDataArray]; // Initialize the initial height of each column [self initColumHeightArray]; // Initialize all cell heights and store them in array [self initAllCellHeight]; } // instantiate the array of position information and height information - (void)initDataArray{// Record the current height of each column, so we only need space for the number of columns. _columHeightArr = [NSMutableArray arrayWithCapacity:_colum]; _cellFrameArr = [NSMutableArray arrayWithCapacity:0]; } // Initialize the initial height of each column - (void)initColumHeightArray{for(int i = 0; i < _colum; i++) { [_columHeightArr addObject:@(_insetSpace.top)]; }} // Initialize the height of all cells, InitAllCellHeight {// Get the number of cells in the first group NSInteger allCellNumber = [self.collectionView numberOfItemsInSection:0]; / / get the width of the entire collectionView CGFloat totalWidth = self. CollectionView. Frame. The size. The width; CGFloat itemAllWidth = totalWidth -_insetSpace. Left - _insetSpace. Right - _distance * (_colum - 1); CGFloat width = itemAllWidth/_colum; // Loop through the height of each cell and add the location information to the arrayfor(int i = 0; i < allCellNumber; NSInteger currentColum = [self getShortColum]; CGFloat xOffset = _insetSpace. Left + currentColum * (width + _distance); CGFloat xOffset = _insetSpace. NSIndexPath *indexPath = [NSIndexPath indexPathForItem: IinSection:0]; / / y offset CGFloat yOffset = [[_columHeightArr objectAtIndex: currentColum]floatValue] + _distance; // Get the height, provided by the implementer CGFloat height = 0.f;if(_delegate && [_delegate respondsToSelector:@selector(waterFlow:heightForCellAtIndexPath:)]) { height = [_delegate waterFlow:self heightForCellAtIndexPath:indexPath]; CGRect frame = CGRectMake(xOffset, yOffset, width, height); / / the attributes are used to store the position information of the current cell indexPath UICollectionViewLayoutAttributes * attributes = [UICollectionViewLayoutAttributes  layoutAttributesForCellWithIndexPath:indexPath]; attributes.frame = frame; // Add location information to the cell size array [_cellFrameArr addObject:attributes]; // Change the height of the current column _columHeightArr[currentColum] = @(frame.size.height + frame.origine. y); }} / / the size of the current cell - (UICollectionViewLayoutAttributes *) layoutAttributesForItemAtIndexPath: (indexPath NSIndexPath *) {return[_cellFrameArr objectAtIndex:indexPath.item]; } / / layout according to the need of the rect to find out the location of the cell information - (NSArray < UICollectionViewLayoutAttributes * > *) the rect layoutAttributesForElementsInRect: (CGRect) {/ / used to store information can show the location of the cell NSMutableArray * temp = [NSMutableArray arrayWithCapacity:0];for (UICollectionViewLayoutAttributes *attributes in_cellFrameArr) {// If the location is in the recT range, the location is loaded into the array.if(CGRectIntersectsRect(attributes.frame, rect)) { [temp addObject:attributes]; }}returntemp; } / / specifies the contentSize collection - (CGSize collectionViewContentSize) {/ / content width specified for collectionView width (horizontal scroll) CGFloat width = self.collectionView.frame.size.width; CGFloat height = [self getLongColum]; CGFloat height = [self getLongColum];returnCGSizeMake(width, height); } - (CGFloat)getLongColum{// Record the longest current column number. __block CGFloat longHeight = 0; / / the enumeration of the array elements [_columHeightArr enumerateObjectsUsingBlock: ^ (id _Nonnull obj, NSUInteger independence idx, BOOL * _Nonnull stop) {if ([obj floatValue] > longHeight) {
            longHeight = [obj floatValue]; currentColum = idx; }}];returnlongHeight + _insetSpace.bottom; } // getShortColum{(NSInteger)getShortColum{// getShortColum = 0; // Assume that the shortest column height isfloat__block CGFloat shortHeight = MAXFLOAT; / / the enumeration of the array elements [_columHeightArr enumerateObjectsUsingBlock: ^ (id _Nonnull obj, NSUInteger independence idx, BOOL * _Nonnull stop) {if ([obj floatValue] < shortHeight) {
            shortHeight = [obj floatValue]; currentColum = idx; }}];return currentColum;
}

@end
Copy the code

Attached: my blog address