前幾篇博客從UICollectionView的基礎應用到設置UICollectionViewFlowLayout更加靈活的進行佈局,但都限制在系統爲咱們準備好的佈局框架中,仍是有一些侷限性,例如,若是我要進行瀑布流似的不定高佈局,前面的方法就很難知足咱們的需求了,以下:數組
這種佈局無疑在app的應用中更加普遍,商品的展現,書架書目的展現,都會傾向於採用這樣的佈局方式,固然,經過自定義FlowLayout,咱們也很容易實現。app
首先,咱們新建一個文件繼承於UICollectionViewFlowLayout:框架
@interface MyLayout : UICollectionViewFlowLayout
爲了演示的方面,這裏我不錯更多的封裝,添加一個屬性,直接讓外界將item個數傳遞進來,咱們把重心方法重寫佈局的方法上:dom
@interface MyLayout : UICollectionViewFlowLayout @property(nonatomic,assign)int itemCount; @end
前面說過,UICollectionViewFlowLayout是一個專門用來管理collectionView佈局的類,所以,collectionView在進行UI佈局前,會經過這個類的對象獲取相關的佈局信息,FlowLayout類將這些佈局信息所有存放在了一個數組中,數組中是UICollectionViewLayoutAttributes類,這個類是對item佈局的具體設置,之後我們在討論這個類。總之,FlowLayout類將每一個item的位置等佈局信息放在一個數組中,在collectionView佈局時,會調用FlowLayout類layoutAttributesForElementsInRect:方法來獲取這個佈局配置數組。所以,咱們須要重寫這個方法,返回咱們自定義的配置數組,另外,FlowLayout類在進行佈局以前,會調用prepareLayout方法,因此咱們能夠重寫這個方法,在裏面對咱們的自定義配置數據進行一些設置。佈局
簡單來講,自定義一個FlowLayout佈局類就是兩個步驟:atom
一、設計好咱們的佈局配置數據 prepareLayout方法中spa
二、返回咱們的配置數組 layoutAttributesForElementsInRect方法中設計
示例代碼以下:code
@implementation MyLayout { //這個數組就是咱們自定義的佈局配置數組 NSMutableArray * _attributeAttay; } //數組的相關設置在這個方法中 //佈局前的準備會調用這個方法 -(void)prepareLayout{ _attributeAttay = [[NSMutableArray alloc]init]; [super prepareLayout]; //演示方便 咱們設置爲靜態的2列 //計算每個item的寬度 float WIDTH = ([UIScreen mainScreen].bounds.size.width-self.sectionInset.left-self.sectionInset.right-self.minimumInteritemSpacing)/2; //定義數組保存每一列的高度 //這個數組的主要做用是保存每一列的總高度,這樣在佈局時,咱們能夠始終將下一個Item放在最短的列下面 CGFloat colHight[2]={self.sectionInset.top,self.sectionInset.bottom}; //itemCount是外界傳進來的item的個數 遍從來設置每個item的佈局 for (int i=0; i<_itemCount; i++) { //設置每一個item的位置等相關屬性 NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0]; //建立一個佈局屬性類,經過indexPath來建立 UICollectionViewLayoutAttributes * attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index]; //隨機一個高度 在40——190之間 CGFloat hight = arc4random()%150+40; //哪一列高度小 則放到那一列下面 //標記最短的列 int width=0; if (colHight[0]<colHight[1]) { //將新的item高度加入到短的一列 colHight[0] = colHight[0]+hight+self.minimumLineSpacing; width=0; }else{ colHight[1] = colHight[1]+hight+self.minimumLineSpacing; width=1; } //設置item的位置 attris.frame = CGRectMake(self.sectionInset.left+(self.minimumInteritemSpacing+WIDTH)*width, colHight[width]-hight-self.minimumLineSpacing, WIDTH, hight); [_attributeAttay addObject:attris]; } //設置itemSize來確保滑動範圍的正確 這裏是經過將全部的item高度平均化,計算出來的(以最高的列位標準) if (colHight[0]>colHight[1]) { self.itemSize = CGSizeMake(WIDTH, (colHight[0]-self.sectionInset.top)*2/_itemCount-self.minimumLineSpacing); }else{ self.itemSize = CGSizeMake(WIDTH, (colHight[1]-self.sectionInset.top)*2/_itemCount-self.minimumLineSpacing); } } //這個方法中返回咱們的佈局數組 -(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{ return _attributeAttay; } @end
自定義完成FlowLayout後,咱們在ViewController中進行使用:orm
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. MyLayout * layout = [[MyLayout alloc]init]; layout.scrollDirection = UICollectionViewScrollDirectionVertical; layout.itemCount=100; UICollectionView * collect = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, 320, 400) collectionViewLayout:layout]; collect.delegate=self; collect.dataSource=self; [collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellid"]; [self.view addSubview:collect]; } -(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{ return 1; } -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return 100; } -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath]; cell.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1]; return cell; }
運行效果就是咱們引言中的截圖。
經過上面的例子,咱們能夠了解,collectionView的item佈局實際上是LayoutAttributes類具體配置的,這個類能夠配置的佈局屬性不止是frame這麼簡單,其中還有許多屬性:
//配置item的佈局位置 @property (nonatomic) CGRect frame; //配置item的中心 @property (nonatomic) CGPoint center; //配置item的尺寸 @property (nonatomic) CGSize size; //配置item的3D效果 @property (nonatomic) CATransform3D transform3D; //配置item的bounds @property (nonatomic) CGRect bounds NS_AVAILABLE_IOS(7_0); //配置item的旋轉 @property (nonatomic) CGAffineTransform transform NS_AVAILABLE_IOS(7_0); //配置item的alpha @property (nonatomic) CGFloat alpha; //配置item的z座標 @property (nonatomic) NSInteger zIndex; // default is 0 //配置item的隱藏 @property (nonatomic, getter=isHidden) BOOL hidden; //item的indexpath @property (nonatomic, strong) NSIndexPath *indexPath; //獲取item的類型 @property (nonatomic, readonly) UICollectionElementCategory representedElementCategory; @property (nonatomic, readonly, nullable) NSString *representedElementKind; //一些建立方法 + (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath; + (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath; + (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;
經過上面的屬性,能夠佈局出各式各樣的炫酷效果,正如一句話:沒有作不到,只有想不到。
專一技術,熱愛生活,交流技術,也作朋友。
——琿少 QQ羣:203317592