OC-UICollectionView implements waterfall stream and ocuicollectionview
UICollectionView implements waterfall stream
There are currently two known solutions for implementing waterfall stream in iOS:
This article introduces the second implementation scheme.
First, we need to customizeUICollectionViewLayout
And then rewrite the following four methods:
The first method is to perform some initialization operations. This method must first call the implementation of the parent class.
The second method returnsUICollectionViewLayoutAttributes
Array
The third method returnsindexPath
LocationUICollectionViewLayoutAttributes
The fourth method is to returnUICollectionView
Scroll range
How to Implement waterfall stream
First, we need to understand the arrangement of waterfall streams. waterfall streams are some irregular controls distributed on the mobile phone screen, then there must be tall and short ones (just like a person's height, hahaha). When the first row is full, it will continue to be arranged. Where should I put this, = the answer is to put it below the shortest in the first row =, and so on, sort it according to this rule.
Now that we understand this, we should write the code.
First, we create two arrays, one containing the layout attribute of the cell, and the other containing the total height of the current cell.
// C stores the layout attributes of all cells @ property (nonatomic, strong) NSMutableArray * attrsArray; // stores the current height of all columns @ property (nonatomic, strong) NSMutableArray * columnHeights; /** content height */@ property (nonatomic, assign) CGFloat contentHeight;
-(Void) prepareLayout {[super prepareLayout]; self. contentHeight = 0; // clear all previously calculated heights, because the method [self. columnHeights removeAllObjects]; for (NSInteger I = 0; I <defacolumcolumncpunt; I ++) {[self. columnHeights addObject: @ (self. edgeInsets. top)];} // put all initialization operations here [self. attrsArray removeAllObjects]; // start to create the layout attribute NSInteger count = [self. collectionView numberOfItemsInSection: 0]; for (NSInteger I = 0; I <count; I ++) {// create the NSIndexPath * indexPath = [NSIndexPath indexPathForItem: I inSection: 0]; // obtain the layout attribute UICollectionViewLayoutAttributes * attrs = [self layoutAttributesForItemAtIndexPath: indexPath]; [self. attrsArray addObject: attrs] ;}}
First, set the cell heightself.edgeInsets.top
Otherwise, it will crash. Then obtain the number of items, and then cyclically retrieveUICollectionViewLayoutAttributes
And add itattsArray
And then- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
This method directly returnsattrsArray
You can.
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; CGFloat collectionViewW = self.collectionView.frame.size.width; CGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right -(self.columnCount - 1) * self.columnMargin) / self.columnCount; CGFloat h = [self.delegate WaterFlowLayout:self heightForRowAtIndexPath:indexPath.item itemWidth:w]; NSInteger destColumn = 0; CGFloat minColumnHeight = [self.columnHeights[0] doubleValue]; for (NSInteger i = 0; i < self.columnCount; i++) { CGFloat columnHeight = [self.columnHeights[i] doubleValue]; if (minColumnHeight > columnHeight) { minColumnHeight = columnHeight; destColumn = i; } } CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin); CGFloat y = minColumnHeight; if (y != self.edgeInsets.top) { y += self.rowMargin; } attrs.frame = CGRectMake(x, y, w, h); self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame)); CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue]; if (self.contentHeight < columnHeight) { self.contentHeight = columnHeight; } return attrs;}
The above method is the code used to calculate the position of an item.indexPath
OfUICollectionViewLayoutAttributes
The core code is as follows:
NSInteger destColumn = 0; CGFloat minColumnHeight = [self.columnHeights[0] doubleValue]; for (NSInteger i = 0; i < self.columnCount; i++) { CGFloat columnHeight = [self.columnHeights[i] doubleValue]; if (minColumnHeight > columnHeight) { minColumnHeight = columnHeight; destColumn = i; } } CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin); CGFloat y = minColumnHeight; if (y != self.edgeInsets.top) { y += self.rowMargin; }
First, we get an identifier.destColumn
Record the column and defineminColumnHeight
Returns the height of the smallest column.self.columnHeights[0]
Here, the default value is the smallest, and then the for loop traversal is performed to obtain the height above the I position. If the value is smaller than the previous minColumnHeight, then the obtained height is the smallest height, and the I value is assigned to destColumn. Then, the value of x is the result of the addition in the code above, and the value of y is to continue to add spacing.
-(CGSize) collectionViewContentSize {// CGFloat maxColumnHeight = [self. columnHeights [0] doubleValue]; // for (NSInteger I = 1; I <DefaultColumnCpunt; I ++) {// obtain the height of column I // CGFloat columnHeight = [self. columnHeights [I] doubleValue]; // if (maxColumnHeight <columnHeight) {// maxColumnHeight = columnHeight; //} return CGSizeMake (0, self. contentHeight + self. edgeInsets. bottom );}
Portal: gitHub