自定義UICollectinviewFlowLayout,即實現瀑布流

IsaMinnick 8年前發布 | 12K 次閱讀 iOS開發 Objective-C開發

來自: http://www.cnblogs.com/xueyao/p/5188321.html

如圖所示,通過實現不規則的網格分布,來顯示出不同的效果。因為集合視圖必須要指定布局還可以顯示,所以自定義布局就可以實現瀑布流的效果。

//創建布局對象
    WaterFlowLayout *flowLayout = [[WaterFlowLayout alloc] init];

flowLayout.delegate = self;
flowLayout.numberOfColumn = 3;

//創建集合視圖
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];</pre> 

因為系統自帶的布局有四個方法,分別實現了item大小,分區間隔,最小行間距,item之間的間隙大小

@protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate>
@optional

  • (CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
  • (UIEdgeInsets)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
  • (CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
  • (CGFloat)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;</pre>

    所以,自定義FlowLayout,并定義協議,以便定義這些方法。

    @protocol WaterFlowLayoutDelegate <NSObject>

//關鍵方法,此方法的作用是返回每一個item的size大小 //數據中原始圖片大小

  • (CGSize)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath; //分區間隔
  • (UIEdgeInsets)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout insetForSectionAtIndex:(NSInteger)section; //得到 item之間的間隙大小
  • (CGFloat)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section; //最小行間距
  • (CGFloat)collectionView:(UICollectionView )collectionView layout:(WaterFlowLayout )collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;

@end

@interface WaterFlowLayout : UICollectionViewLayout

//瀑布流一共多少列 @property (nonatomic, assign) NSUInteger numberOfColumn;

@property (nonatomic, assign) id<WaterFlowLayoutDelegate>delegate;</pre>

看圖可知,最小高的的item,將作為下一列item的起點。

@interface WaterFlowLayout ()

//存放每一列的高度 @property (nonatomic, retain) NSMutableArray *columnHeightsArray;

//存放 每一個item的 屬性 包含 frame以及下標 @property (nonatomic, retain) NSMutableArray *attributesArray;

@end

@implementation WaterFlowLayout

//獲取最小高度的方法

  • (CGFloat)minHeight { CGFloat min = 100000; for (NSNumber *height in _columnHeightsArray) {
      CGFloat h = [height floatValue];
      if (min > h) {
          min = h;
      }
    
    } return min; }

//獲取最大值

  • (CGFloat)maxHeight { CGFloat max = 0; for (NSNumber *height in _columnHeightsArray) {
      CGFloat h = [height floatValue];
      if (max < h) {
          max = h;
      }
    
    } return max; }

//找到最小高的下標

  • (NSUInteger)indexOfMinHeight { NSUInteger index = 0; for (int i = 0; i < [_columnHeightsArray count]; i ++) {
      CGFloat height = [_columnHeightsArray[i] floatValue];
      if (height == [self minHeight]) {
          index = i;
          return index;
      }
    
    } return index; }

//重寫父類的布局方法

  • (void)prepareLayout { [super prepareLayout];

    _attributesArray = [[NSMutableArray alloc] init];

    _columnHeightsArray = [[NSMutableArray alloc] initWithCapacity:self.numberOfColumn];

    //給列高數組里面的對象賦初值 for (int i = 0; i < self.numberOfColumn; i ++) {

      [_columnHeightsArray addObject:@0.0];
    

    }

    CGFloat totalWidth = self.collectionView.frame.size.width;

    //創建 每個item frame中的x、y CGFloat x = 0; CGFloat y = 0;

    NSUInteger itemCount = [self.collectionView numberOfItemsInSection:0];

    for (int i = 0; i < itemCount; i ++) {

      //得到集合視圖中 列間隙的個數
      NSUInteger numberOfSpace = self.numberOfColumn - 1;
    
      //代理對象執行代理方法,得到 item之間的間隙大小
      CGFloat spaceWidth = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:0];
    
      //求每列的寬度,也就是每個item的width
      CGFloat width = (totalWidth - spaceWidth * numberOfSpace) / self.numberOfColumn;
    //獲取每一個itemSize的大小
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

    //數據中原始圖片大小
    CGSize imageSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];

    //通過 約分公式得到固定寬之后的高度是多少
    CGFloat height = width * imageSize.height / imageSize.width;


    UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    //記錄每一個item的大小和位置
    attribute.frame = CGRectMake(x, y, width, height);

    //數組保存每個item的位置信息
    [_attributesArray addObject:attribute];

    NSLog(@"item = %d",i);
    NSLog(@"x = %.2f y = %.2f width = %.2f height = %.2f",x,y,width,height);

    //求列高最小的那一列的下標
    NSUInteger minHeightIndex = [self indexOfMinHeight];

    //求出最小列的高度
    CGFloat minHeight = [_columnHeightsArray[minHeightIndex] floatValue];

    //求出行高
    CGFloat lineHeight = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:0];

    //上一次總的列高 加上 行高 加上新加上的item的height,才是現在這一列的總高度
    //minHeight為最小列現在的高度
    //lineHeight為行間距
    //height為新加的item的高
    _columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height];

    //重新算最小列高的下標
    minHeightIndex = [self indexOfMinHeight];

    //算下一次新加的item的x和y值
    x = (spaceWidth + width) * minHeightIndex;

    y = [self minHeight];
}

}

//重寫這個方法,可以返回集合視圖的總高度

  • (CGSize)collectionViewContentSize { return CGSizeMake(self.collectionView.frame.size.width, [self maxHeight]); }
  • (NSArray )layoutAttributesForElementsInRect:(CGRect)rect { return _attributesArray; }</pre>

    注意,最后一個方法的實現,即- (NSArray )layoutAttributesForElementsInRect:(CGRect)rect,如果這個方法不寫,集合視圖是顯示不出來的,這個方法是次保存的每個item的信息重新告訴集合視圖,進行顯示。</p> </div>

 本文由用戶 IsaMinnick 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!