[Code Note] custom Layout for waterfall flow and waterfall Layout
The file directory is as follows:
The animation is as follows:
1 // ViewController file 2 3 # import "ViewController. h "4 # import" LYWaterFlowLayout. h "5 # import" LYWaterCell. h "6 # import" LYShopModel. h "7 8 @ interface ViewController () <UICollectionViewDataSource> 9 @ property (nonatomic, strong) NSArray * shops; 10 11 12 @ end13 14 @ implementation ViewController15 static NSString * ID = @ "water"; 16 17-(NSArray *) shops {18 19 if (_ shops = nil) {20 // 1. read File 21 NSString * path = [[NSBundle mainBundle] pathForResource: @ "1. plist "ofType: nil]; 22 NSArray * dictArray = [NSArray arrayWithContentsOfFile: path]; 23 // 2. dictionary conversion model 24 bytes * tempArray = [NSMutableArray array]; 25 for (NSDictionary * dict in dictArray) {26 LYShopModel * shop = [LYShopModel shopWithDict: dict]; 27 [tempArray addObject: shop]; 28 29} 30 _ shops = tempArray; 31 32 33 34} 35 return _ shops; 36} 37 38-(void) viewDidLoad {39 [super viewDidLoad]; 40 // Do any additional setup after loading the view, typically from a nib.41 // 0. custom Layout 42 LYWaterFlowLayout * waterFlowLayout = [[LYWaterFlowLayout alloc] init]; 43 // 0. 1. pass the external array to the internal 44 waterFlowLayout. shops = self. shops; 45 46 // 1. create collectionView47 UICollectionView * collectionView = [[UICollectionView alloc] initWithFrame: CGRectMake (0, 0, self. view. frame. size. width, self. view. frame. size. height) collectionViewLayout: waterFlowLayout]; 48 // 2. set the data source 49 collectionView. dataSource = self; 50 // 3. set proxy 51 // collectionView. delegate = self; 52 53 54 // 3. add 55 [self. view addSubview: collectionView]; 56 // 4. register cell57 [collectionView registerNib: [UINib nibWithNibName: @ "LYWaterCell" bundle: nil] region: ID]; 58 59 60} 61 62-(NSInteger) numberOfSectionsInCollectionView :( UICollectionView *) collectionView {63 64 return 1; 65 66} 67 68-(NSInteger) collectionView :( UICollectionView *) collectionView numberOfItemsInSection :( NSInteger) section {69 70 return self. shops. count; 71} 72 73-(UICollectionViewCell *) collectionView :( UICollectionView *) collectionView cellForItemAtIndexPath :( NSIndexPath *) indexPath {74 75 76 // 1. create cell77 78 LYWaterCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier: ID forIndexPath: indexPath]; 79 // 2. value: 80 // 81 // cell. backgroundColor = [UIColor redColor]; 82 // 2.1 obtain the model 83 LYShopModel * shop = self. shops [indexPath. item]; 84 cell. shop = shop; 85 86 cell. indexPath = indexPath; 87 // 3. return cell88 return cell; 89 90 91} 92 93 @ end
1 // LYWaterCell file 2 # import <UIKit/UIKit. h> 3 @ class LYShopModel; 4 5 @ interface LYWaterCell: UICollectionViewCell 6 @ property (nonatomic, strong) LYShopModel * shop; 7 8 @ property (nonatomic, strong) NSIndexPath * indexPath; 9 10 @ end11 12 13 14 15 16 # import "LYWaterCell. h "17 # import" LYShopModel. h "18 19 @ interface LYWaterCell () 20 21 @ property (weak, nonatomic) IBOutlet UIImageView * iconView; 22 @ property (weak, nonatomic) IBOutlet UILabel * priceLabel; 23 24 @ end25 @ implementation LYWaterCell26-(void) setShop :( LYShopModel *) shop {27 28 _ shop = shop; 29 30 self. iconView. image = [UIImage imageNamed: shop. icon]; 31 // self. priceLabel. text = shop. price; 32 33} 34-(void) setIndexPath :( NSIndexPath *) indexPath {35 36 _ indexPath = indexPath; 37 self. priceLabel. text = self. shop. price; 38 39} 40 41 @ end
1 // LYWaterFlowLayout file 2 # import <UIKit/UIKit. h> 3 4 @ interface LYWaterFlowLayout: UICollectionViewFlowLayout 5 6 7 8 @ property (nonatomic, strong) NSArray * shops; 9 10 11 @ end 12 13 14 15 16 17 int const column = 3; 18 # import "LYWaterFlowLayout. h "19 # import" LYShopModel. h "20 21 @ interface LYWaterFlowLayout () 22 23 @ property (nonatomic, strong) NSMutableArray * maxYs; 24 @ end 25 26 @ implementation LYWaterFlowLayout 27-(NSMutableArray *) maxYs {28 29 if (_ maxYs = nil) {30 _ maxYs = [NSMutableArray array]; 31 NSLog (@ "% @", _ maxYs ); 32 33} 34 35 return _ maxYs; 36} 37 38/** 39 * is used to set the item attribute of each corresponding position 40*41 * @ param indexPath is used to determine the specific position of each item 42*43 * @ return is used to set each item attributes 44 */45-(UICollectionViewLayoutAttributes *) layoutAttributesForItemAtIndexPath :( NSIndexPath *) indexPath {46 // NSLog (@ "layoutAttributesForItemAtIndexPath"); 47 // 1. determine the upper left bottom right margin 48 49 UIEdgeInsets edge = UIEdgeInsetsMake (10, 10, 10); 50 // 2. determine width 51 // 2.1 determine Number of columns 52 53 // 2.2 determine row spacing and column spacing 54 CGFloat rowMargin = 10; 55 CGFloat colMargin = 10; 56 57 CGFloat itemW = (self. collectionView. frame. size. width-edge. left-edge. right-(column-1) * colMargin)/column; 58 // 3. determine the height 59 // 3.1 obtain the corresponding item Model 60 LYShopModel * shop = self. shops [indexPath. item]; 61 // itemW/itemh = shop. width/shop. height; 62 63 CGFloat itemH = shop. height * itemW/shop. width; 64 65 // CGFloat itmeH = 100 + arc4random_uniform (100); 66 // 4. determine the position 67 68 // 4.1 obtain the minimum maximum y Value 69 // 4.2 Use a value to record the minimum maximum y value 70 CGFloat minMaxY = MAXFLOAT; 71 // column number of the smallest and largest y value in the 4.3 record; 72 NSInteger minMaxCol = 0; 73 for (int I = 0; I <column; I ++) {74 CGFloat maxY = [self. maxYs [I] doubleValue]; 75 if (maxY <minMaxY) {76 minMaxY = maxY; 77 minMaxCol = I; 78} 79} 80 // 4.4 set item x value 81 CGFloat itemX = edge. left + (itemW + colMargin) * minMaxCol; 82 CGFloat itemY = minMaxY + rowMargin; 83 // 5. obtain the attributes of each item in the corresponding position. 84 UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath: indexPath]; 85 // 6. set the frame 86 attr of the attribute. frame = CGRectMake (itemX, itemY, itemW, itemH); 87 // 7. the maximum value of y is 88 // minMaxY = CGRectGetMaxY (attr. frame); 89 self. maxYs [minMaxCol] = @ (CGRectGetMaxY (attr. frame); 90 91 92 93 // 8. return attribute 94 return attr; 95 96} 97/** 98 * is used to set all attributes within the specified range 99*100 * @ param rect <# rect description #> 101*102 * @ return <# return value description #> 103 */104-(NSArray <UICollectionViewLayoutAttributes *> *) layoutAttributesForElementsInRect :( CGRect) rect {105 // NSLog (@ "layoutAttributesForElementsInRect"); 106 // 0. clear all original values 107 // [self. maxYs removeAllObjects]; 108 // 1. set the value of the array to 109 for (int I = 0; I <column; I ++) {110 // [self. maxYs addObject: @ (0)]; 111 self. maxYs [I] = @ (0); 112} 113 114 115 // 2. create a variable array 116 NSMutableArray * attrs = [NSMutableArray array]; 117 118 119 // 3. obtain the number of attributes of all items. 120 NSInteger count = [self. collectionView numberOfItemsInSection: 0]; 121 // 4. traverse multiple times and add the corresponding property value 122 for (int I = 0; I <count; I ++) {123 NSIndexPath * indexPath = [NSIndexPath indexPathForItem: I inSection: 0]; 124 125 UICollectionViewLayoutAttributes * attr = [self layoutAttributesForItemAtIndexPath: indexPath]; 126 127 128 [attrs addObject: attr]; // NSLog (@ "% @", attr ); 129 130} 131 return attrs; 132 133 134} 135-(BOOL) returns :( CGRect) newBounds {136 // NSLog (@ "shouldInvalidateLayoutForBoundsChange" called); 137 return YES; 138} 139/** 140 * is used to set the rolling range of collectionView to 141*142 * @ return <# return value description #> 143 */144 145-(CGSize) collectionViewContentSize {146 // NSLog (@ "collectionViewContentSize called"); 147 // 1. obtain the maximum y value 148 CGFloat maxMaxY = 0; 149 // 1. 1. the maximum y value of a record is 150 if (self. maxYs. count) {151 maxMaxY = [self. maxYs [0] doubleValue]; 152 for (int I = 1; I <column; I ++) {153 // 1.2 get each value 154 CGFloat maxY = [self. maxYs [I] doubleValue]; 155 if (maxY> maxMaxY) {156 maxY = maxY; 157} 158 159 160} 161 162 163 return CGSizeMake (0, maxMaxY ); 165 166 167} 168 169 @ end
1 // LYShopModel file 2 # import <Foundation/Foundation. h> 3 4 @ interface LYShopModel: NSObject 5 @ property (nonatomic, copy) NSString * icon; 6 @ property (nonatomic, copy) NSString * price; 7 @ property (nonatomic, assign) int height; 8 @ property (nonatomic, assign) int width; 9-(instancetype) initWithDict :( NSDictionary *) dict; 10 + (instancetype) shopWithDict :( NSDictionary *) dict; 11 12 @ end13 14 15 16 17 18 # import "LYShopModel. h "19 20 @ implementation LYShopModel21 22-(instancetype) initWithDict :( NSDictionary *) dict {23 24 if (self = [super init]) {25 [self setValuesForKeysWithDictionary: dict]; 26} 27 return self; 28} 29 + (instancetype) shopWithDict :( NSDictionary *) dict {30 31 return [[self alloc] initWithDict: dict]; 32} 33 34 @ end