自定义UICollectionViewLayout(适用于多个section)

一、自定义layout主要方法

  重写系统的- (void)prepareLayout  方法;

  其实就是计算每个cell的frame和其它相关属性。

  

 二、在网上看了好多自定义的layout 但是没有多section的,就整了这个……

  全部代码:

.h文件
@class ForeverGuardFlowLayout;
@protocol ForeverGuardFlowLayoutDelegate <NSObject>
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(ForeverGuardFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
@end

@interface ForeverGuardFlowLayout : UICollectionViewFlowLayout

@property(nonatomic, assign)NSUInteger numberOfColumn;//列数
@property(nonatomic, assign)id<ForeverGuardFlowLayoutDelegate>delegate;

@end

  

  1 @interface ForeverGuardFlowLayout()
  2 //存放每一列的高度
  3 @property (nonatomic, retain) NSMutableArray *columnHeightsArray;
  4 
  5 //每个section的每一列的高度
  6 @property (nonatomic, retain) NSMutableArray *collectionHeightsArray;
  7 
  8 //存放每一个cell的属性
  9 @property (nonatomic, retain) NSMutableArray *attributesArray;
 10 
 11 
 12 @end
 13 @implementation  ForeverGuardFlowLayout
 14 
 15 
 16 /**
 17  每个区的最小高度
 18 
 19  @param section 区索引
 20  @return 高度
 21  */
 22 - (CGFloat)minHeightWithSection:(NSInteger)section{
 23     CGFloat min = 1000000;
 24     for (NSNumber *height in _collectionHeightsArray[section]) {
 25         if (min > [height floatValue]) {
 26             min = [height floatValue];
 27         }
 28     }
 29     return min;
 30 }
 31 
 32 
 33 /**
 34  每个区的初始Y坐标
 35 
 36  @param section 区索引
 37  @return Y坐标
 38  */
 39 - (CGFloat)maxHeightWithSection:(NSInteger)section{
 40     
 41     if (section>0) {
 42         CGFloat max = 0;
 43         for (int i=0; i<section; i++) {
 44             max += [self maxHeightAboutSection:_collectionHeightsArray[i]];
 45         }
 46         return max;
 47     }else{
 48         return 0;
 49     }
 50     
 51 }
 52 
 53 
 54 /**
 55  每个区的最大高度
 56 
 57  @param dataArr 每个区的所有列的高度
 58  @return 最大高度
 59  */
 60 - (CGFloat)maxHeightAboutSection:(NSMutableArray *)dataArr{
 61     CGFloat max = 0;
 62     for (NSNumber *heigth  in dataArr) {
 63         if (max < [heigth floatValue]) {
 64             max = [heigth floatValue];
 65         }
 66     }
 67     return max;
 68 
 69 }
 70 
 71 
 72 /**
 73  collectionView的显示高度
 74  */
 75 - (CGFloat)collectionHeight{
 76     CGFloat max = 0;
 77     for (NSMutableArray *sectionArr in _collectionHeightsArray) {
 78         max += [self maxHeightAboutSection:sectionArr];
 79     }
 80     return max;
 81 }
 82 
 83 
 84 /**
 85  当前区的最小高度的索引
 86 
 87  @param section 当前区
 88  @return 最小高度的索引
 89  */
 90 - (NSUInteger)indexOfMinHeightWithSection:(NSInteger)section{
 91     NSUInteger index  = 0;
 92     NSMutableArray *sectionArr = _collectionHeightsArray[section];
 93     for (int i=0; i<sectionArr.count; i++) {
 94         CGFloat height = [sectionArr[i] floatValue];
 95         if (height == [self minHeightWithSection:section]) {
 96             index = i;
 97             return index;
 98         }
 99     }
100     return index;
101 }
102 
103 
104 /**
105  重写系统prepareLayout方法 (设置item的坐标等属性)
106  */
107 - (void)prepareLayout{
108     [super prepareLayout];
109     
110     _attributesArray = [[NSMutableArray alloc] init];
111     
112     _columnHeightsArray = [NSMutableArray arrayWithCapacity:self.numberOfColumn];
113     
114     NSUInteger sectionCount = [self.collectionView numberOfSections];
115     _collectionHeightsArray = [NSMutableArray arrayWithCapacity:sectionCount];
116     
117     for (int index = 0; index<sectionCount; index++) {
118         NSMutableArray *columnArr = [NSMutableArray array];
119         for (int i=0; i<self.numberOfColumn; i++) {
120             [columnArr addObject:@0.0];
121         }
122         [_collectionHeightsArray addObject:columnArr];
123     }
124     
125     CGFloat totalWidth = self.collectionView.frame.size.width;
126     
127     CGFloat x = 0;
128     CGFloat y = 0;
129     
130     for (int index= 0; index<sectionCount; index++) {
131         NSUInteger  itemCount = [self.collectionView numberOfItemsInSection:index];
132         x = 0;
133         y = [self maxHeightWithSection:index];
134         for (int i=0; i<itemCount; i++) {
135             NSUInteger numberIfSoace = self.numberOfColumn-1;
136             CGFloat spaceWidth = 7.5;//item左右间距
137             CGFloat width = (totalWidth - spaceWidth*numberIfSoace)/self.numberOfColumn;
138             
139             NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:index];
140             
141             CGSize imageSize =[self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
142             
143             CGFloat height = width * imageSize.height / imageSize.width;
144             
145             UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
146             
147             attributes.frame = CGRectMake(x, y, width, height);
148             [_attributesArray addObject:attributes];
149             
150             
151             NSUInteger minHeightIndex = [self indexOfMinHeightWithSection:index];
152             
153             CGFloat minHeight = [_collectionHeightsArray[index][minHeightIndex] floatValue];
154             CGFloat lineHeight = 7.5;//item上下间距
155             
156             _collectionHeightsArray[index][minHeightIndex] = [NSNumber numberWithFloat:minHeight+lineHeight+height];
157             minHeightIndex = [self indexOfMinHeightWithSection:index];
158             
159             x = (spaceWidth + width) * minHeightIndex;
160             
161             y += [self minHeightWithSection:index];
162             
163         }
164         
165     }
166     
167 }
168 
169 
170 /**
171  返回collectionView的界面显示大小
172  */
173 - (CGSize)collectionViewContentSize{
174     return  CGSizeMake(self.collectionView.frame.size.width, [self collectionHeight]);
175 }
176 
177 
178 /**
179  将所有的layoutAttributes重写布局
180  */
181 - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
182     return _attributesArray;
183 }
184 @end
.m文件
@interface ForeverGuardFlowLayout()
//存放每一列的高度
@property (nonatomic, retain) NSMutableArray *columnHeightsArray;
//每个section的每一列的高度
@property (nonatomic, retain) NSMutableArray *collectionHeightsArray;
//存放每一个cell的属性
@property (nonatomic, retain) NSMutableArray *attributesArray;

@end
@implementation  ForeverGuardFlowLayout

/**
 每个区的最小高度
 
 @param section 区索引
 @return 高度
 */
- (CGFloat)minHeightWithSection:(NSInteger)section{
    CGFloat min = 1000000;
    for (NSNumber *height in _collectionHeightsArray[section]) {
        if (min > [height floatValue]) {
            min = [height floatValue];
        }
    }
    return min;
}

/**
 每个区的初始Y坐标
 
 @param section 区索引
 @return Y坐标
 */
- (CGFloat)maxHeightWithSection:(NSInteger)section{
    
    if (section>0) {
        CGFloat max = 0;
        for (int i=0; i<section; i++) {
            max += [self maxHeightAboutSection:_collectionHeightsArray[i]];
        }
        return max;
    }else{
        return 0;
    }
    
}


/**
 每个区的最大高度
 
 @param dataArr 每个区的所有列的高度
 @return 最大高度
 */
- (CGFloat)maxHeightAboutSection:(NSMutableArray *)dataArr{
    CGFloat max = 0;
    for (NSNumber *heigth  in dataArr) {
        if (max < [heigth floatValue]) {
            max = [heigth floatValue];
        }
    }
    return max;
    
}

/**
 collectionView的显示高度
 */
- (CGFloat)collectionHeight{
    CGFloat max = 0;
    for (NSMutableArray *sectionArr in _collectionHeightsArray) {
        max += [self maxHeightAboutSection:sectionArr];
    }
    return max;
}

/**
 当前区的最小高度的索引
 
 @param section 当前区
 @return 最小高度的索引
 */
- (NSUInteger)indexOfMinHeightWithSection:(NSInteger)section{
    NSUInteger index  = 0;
    NSMutableArray *sectionArr = _collectionHeightsArray[section];
    for (int i=0; i<sectionArr.count; i++) {
        CGFloat height = [sectionArr[i] floatValue];
        if (height == [self minHeightWithSection:section]) {
            index = i;
            return index;
        }
    }
    return index;
}


/**
 重写系统prepareLayout方法 (设置item的坐标等属性)
 */
- (void)prepareLayout{
    [super prepareLayout];
    _attributesArray = [[NSMutableArray alloc] init];
    _columnHeightsArray = [NSMutableArray arrayWithCapacity:self.numberOfColumn];
    NSUInteger sectionCount = [self.collectionView numberOfSections];
    _collectionHeightsArray = [NSMutableArray arrayWithCapacity:sectionCount];
    for (int index = 0; index<sectionCount; index++) {
        NSMutableArray *columnArr = [NSMutableArray array];
        for (int i=0; i<self.numberOfColumn; i++) {
            [columnArr addObject:@0.0];
        }
        [_collectionHeightsArray addObject:columnArr];
    }
    CGFloat totalWidth = self.collectionView.frame.size.width;
    
    CGFloat x = 0;
    CGFloat y = 0;
    
    for (int index= 0; index<sectionCount; index++) {
        NSUInteger  itemCount = [self.collectionView numberOfItemsInSection:index];
        x = 0;
        y = [self maxHeightWithSection:index];
        for (int i=0; i<itemCount; i++) {
            NSUInteger numberIfSoace = self.numberOfColumn-1;
            CGFloat spaceWidth = 7.5;//item左右间距
            CGFloat width = (totalWidth - spaceWidth*numberIfSoace)/self.numberOfColumn;
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:index];
            CGSize imageSize =[self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
            CGFloat height = width * imageSize.height / imageSize.width;
            UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
            attributes.frame = CGRectMake(x, y, width, height);
            [_attributesArray addObject:attributes];
            
            NSUInteger minHeightIndex = [self indexOfMinHeightWithSection:index];
            CGFloat minHeight = [_collectionHeightsArray[index][minHeightIndex] floatValue];
            CGFloat lineHeight = 7.5;//item上下间距
            
            _collectionHeightsArray[index][minHeightIndex] = [NSNumber numberWithFloat:minHeight+lineHeight+height];
            minHeightIndex = [self indexOfMinHeightWithSection:index];
            
            x = (spaceWidth + width) * minHeightIndex;
            y = [self minHeightWithSection:index]+[self maxHeightWithSection:index];
        }
    }
}

/**
 返回collectionView的界面显示大小
 */
- (CGSize)collectionViewContentSize{
    return  CGSizeMake(self.collectionView.frame.size.width, [self collectionHeight]);
}

/**
 将所有的layoutAttributes重写布局
 */
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
    return _attributesArray;
}
@end
ForeverGuard博客园
原文地址:https://www.cnblogs.com/xianfeng-zhang/p/6401117.html