iOS瀑布流布局

看完千篇一律的UI布局之后,當我們看到瀑布流的布局是不是覺得有種耳目一新的感覺呢?今天我們就說一下如果實現瀑布流,對于瀑布流,現在iOS中總共存在著三種實現方法.

  • 1.實現瀑布流的布局,我們需要計算每一張圖片的尺寸大小,然后根據列數布局到我們的UIScrollView上去
  • 2.UITableView實現瀑布流效果,就是每一列都是一個視圖.
  • 3.UICollectionView實現瀑布流就是對UICollectionView的UICollectionViewLayout重寫
瀑布流.gif

實現思想:

就是把UICollectionView分成三列,由數組保存每一列的高度,然后每次設置UICollectionViewLayoutAttributes的時候,獲取最短一列,計算出圖片的size,然后添加到最短一列上面。

具體代碼

自定義布局的實現.h

#import <UIKit/UIKit.h>
@class WaterLayout;

//協議
@protocol WaterLayoutDelegate <NSObject>

//代理方法 返回item的高度
- (CGFloat)waterLayout:(WaterLayout *)waterLayout heightForRowAtIndexPath:(NSInteger )index itemWidth:(CGFloat )itemWidth;

@end


@interface WaterLayout : UICollectionViewLayout

@property (nonatomic,assign) CGFloat columnMargin;//列間距

@property (nonatomic,assign) CGFloat rowMargin;//行間距

@property (nonatomic,assign) UIEdgeInsets edge;//邊緣間距

@property (nonatomic,assign) NSInteger columnCount;//列數

@property (nonatomic,assign) id<WaterLayoutDelegate> delegate;//代理


@end

自定義布局的實現.m


#import "WaterLayout.h"

@interface WaterLayout ()
@property (nonatomic,strong) NSMutableArray *attributesArray;   //存放所有cell的布局屬性
@property (nonatomic,strong) NSMutableArray *allColumnMaxYArray; //所有列的高度
@property (nonatomic,assign) CGFloat contentSizeHeight;//內容的高度
@end
@implementation WaterLayout

- (NSMutableArray *)attributesArray {

    if (!_attributesArray) {
        _attributesArray = [NSMutableArray array];
    }

    return _attributesArray;

}


- (NSMutableArray *)allColumnMaxYArray {
    if (!_allColumnMaxYArray) {
        _allColumnMaxYArray  = [NSMutableArray array];
        
    }
    return _allColumnMaxYArray;


}
- (void)prepareLayout {

    [super prepareLayout];
    
    self.contentSizeHeight = 0;

     //先清空數組
    [self.allColumnMaxYArray removeAllObjects];
    
    for (NSInteger i = 0; i < self.self.columnCount; i++) {
        
        [self.allColumnMaxYArray addObject:@(self.self.edge.top)];
    }
    
    //開始創建每一個cell對應的布局屬性
    //一共有多少個cell
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    
    for (int i = 0; i < count; i++) {
        
        //獲取i位置上的索引
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        
        //獲取每個cell的布局屬性
        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];

        //添加
        [self.attributesArray addObject:attributes];
        
    }
    

    
}


/**
 *  這個方法會多次調用
 */
//cell的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    
 
    return self.attributesArray;
}



//indexPath對應cell的布局屬性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {

    //為這個cell創建布局屬性
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    //collectionViewW
    CGFloat collectionViewW = self.collectionView.frame.size.width;
 
    
    //找出高度最短的那一列
     NSInteger column = 0;
    
    //默認第一列的高度最短
     CGFloat minColumnHeight = [self.allColumnMaxYArray[0] doubleValue];
    //遍歷數組所有值
    for (NSInteger i = 1; i < self.self.columnCount; i++) {
        
      //取出每一列的高度
        CGFloat columnHeight = [self.allColumnMaxYArray[i] doubleValue];
        //判斷高度
        if (minColumnHeight >columnHeight) {
            minColumnHeight = columnHeight;
            //最短列賦值給columnY
            column = i;
        }
        
    }
   
    
    //設置布局
    
    CGFloat w = (collectionViewW - self.edge.left - self.edge.right - (self.columnCount - 1)*self.self.columnMargin) / self.columnCount;
    
    CGFloat x = self.edge.left + column * (w + self.columnMargin);
    
    CGFloat y = minColumnHeight;
    
    //如果不是第一行時
    if (y != self.edge.top) {
        y += self.rowMargin;
    }
    
    //高度由外界決定,通過delegate
    CGFloat h = [self.delegate waterLayout:self heightForRowAtIndexPath:indexPath.row itemWidth:w];
    
    //設置frame
    attributes.frame = CGRectMake(x, y, w, h);
    
    //更新最短列的高度
    self.allColumnMaxYArray[column] = @(CGRectGetMaxY(attributes.frame));
    
    //記錄最大高度
    CGFloat columHeight = [self.allColumnMaxYArray[column] doubleValue];
    if (self.contentSizeHeight < columHeight) {
        self.contentSizeHeight = columHeight;
    }
    
    return attributes;
}


//collectionView的ContentSize
- (CGSize)collectionViewContentSize {

 
    //最大高度+self.edge底部高度
    return CGSizeMake(0, self.contentSizeHeight+self.edge.bottom);
}
@end

外界使用布局方式


#import "ViewController.h"
#import "WaterLayout.h"
#import "ShopModel.h"
#import "ShopViewCell.h"
@interface ViewController ()<UICollectionViewDataSource,WaterLayoutDelegate>
@property (nonatomic,strong) NSMutableArray *shopModelArray;
@end

@implementation ViewController



- (NSMutableArray *)shopModelArray {

    if (!_shopModelArray) {
        _shopModelArray = [NSMutableArray array];
    }


    return _shopModelArray;

}


- (void)setData {


    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"1.plist" ofType:nil]];

    for (NSDictionary *dic in array) {
        
        ShopModel *shop = [[ShopModel alloc] init];
        
        [shop setValuesForKeysWithDictionary:dic];
        
        [self.shopModelArray addObject:shop];
        
    }
  
}


- (void)viewDidLoad {
    [super viewDidLoad];
   
    //加載數據
    [self setData];

    [self setLayout];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)setLayout {

    WaterLayout *layout = [[WaterLayout alloc] init];
    
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
    collectionView.backgroundColor = [UIColor whiteColor];
    
    layout.delegate = self;
    layout.columnCount = 3;
    layout.columnMargin = 10;
    layout.rowMargin = 10;
    layout.edge = UIEdgeInsetsMake(10, 10, 10, 10);
    collectionView.dataSource =self;
    
    [self.view addSubview:collectionView];
    
    
    [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([ShopViewCell class]) bundle:nil] forCellWithReuseIdentifier:@"shop"];
}

- (NSInteger )numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;

}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {


    return self.shopModelArray.count;

}



- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    ShopViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"shop" forIndexPath:indexPath];
 
    [cell setCellBasicInfoWithModel:self.shopModelArray[indexPath.row]];
 
    return cell;
}

#pragma mark -----waterLayoutDelegate
- (CGFloat)waterLayout:(WaterLayout *)waterLayout heightForRowAtIndexPath:(NSInteger)index itemWidth:(CGFloat)itemWidth {
    
    ShopModel *shop = self.shopModelArray[index];
    
    return itemWidth*shop.h/shop.w;

}

cell和model我就不展示了,顯得代碼占得太多了,只要會了思想,相信大家不難實現,在稍加封裝,將上面的幾個屬性,寫成代理方法,更加合理些.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容