This time suddenly think of a very long ago to use the knowledge-waterfall flow, originally want to use a simple method, found himself went astray, finally can only malicious to rewrite uicollectionviewflowlayout. Below I will implement the waterfall flow in two ways, And a bug that will introduce the first implementation.
<1> the first Kind
The effect diagram looks like this:
The idea of this realization method:
1 First call the random function, generate the random height, and save it to the array
-(Cgsize) CollectionView: (Uicollectionview *) CollectionView layout: (uicollectionviewlayout *) collectionviewlayout Sizeforitematindexpath: (Nsindexpath *) Indexpath {
cgfloat cellw = m;
CGFloat CELLH = + (Arc4random ()%);
[Self.heightarraym addobject:@ (CELLH)];
Return Cgsizemake (CELLW, CELLH);
}
2 where the frame of the cell is set, the height of the cell is determined by taking the remainder, and the frame of the cell is set.
Disadvantages: In fact, the drawbacks of this method, believe that from the above dynamic diagram can be seen, when the top slide, due to the cell cycle mechanism, the following cell will disappear, but because of high inconsistency, while the cancellation of the last row of the cell, so the following cell on the screen will disappear.
The source code for the first method is attached below:
#import "ViewController.h" #define margin #define COUNT 3 #define Cellheight [Self.heightarraym[indexpath.row] Floatv
Alue] Static NSString * Const ID = @ "Cell"; @interface Viewcontroller () <uicollectionviewdelegate, Uicollectionviewdatasource,
Uicollectionviewdelegateflowlayout> @property (Weak, nonatomic) Iboutlet Uicollectionview *collectionview;
@property (nonatomic, strong) Nsmutablearray *heightarraym; @end @implementation Viewcontroller-(Nsmutablearray *) Heightarraym {if (_heightarraym = = nil) {_heightarraym =
[Nsmutablearray array];
return _heightarraym;
}-(void) viewdidload {[Super viewdidload];
[Self.collectionview Registerclass:[uicollectionviewcell class] forcellwithreuseidentifier:id];
Self.collectionView.dataSource = self;
Self.collectionView.delegate = self;
Set collectionview [self setupcollectionview]; }//Set CollectionView layout-(Uicollectionviewflowlayout *) setupcollectionlayout {uicollectionviewflowlayout * FlowLayout= [[[Uicollectionviewflowlayout alloc] init];
flowlayout.minimuminteritemspacing = margin;
flowlayout.minimumlinespacing = margin;
Flowlayout.sectioninset = uiedgeinsetsmake (margin, margin, margin, margin);
return flowlayout; }//Set CollectionView-(void) Setupcollectionview {self.collectionView.collectionViewLayout =[self
Setupcollectionlayout]; } #pragma mark-uicollectionviewdatasouce-(Nsinteger) CollectionView: (Uicollectionview *) CollectionView
Numberofitemsinsection: (Nsinteger) section {return 60;} -(Uicollectionviewcell *) CollectionView: (Uicollectionview *) CollectionView Cellforitematindexpath: (NSIndexPath *) Indexpath {Uicollectionviewcell *cell = [Self.collectionview dequeuereusablecellwithreuseidentifier:id forIndexPath:
Indexpath];
How many rows are currently in nsinteger NUM1 = Indexpath.row/count;
Current number of columns int num2 = indexpath.row% count;
CGFloat CELLX = num2 * + (num2 + 1) * margin;
CGFloat celly = 0; for (int i = 0; i < num1 i++) {NSINteger position = num2 + i * 3;
Celly + = [Self.heightarraym[position] floatvalue] + margin;
} cgfloat CELLW = 100;
CGFloat CELLH = cellheight;
Cell.frame = CGRectMake (Cellx, celly, CELLW, CELLH);
Cell.backgroundcolor = [Uicolor Redcolor]; Cell.backgroundcolor = [Uicolor colorwithred: (arc4random ()%)/250.0 green: (Arc4random ()%)/250.0 blue: (Arc4ran
Dom ()%)/250.0 alpha:1.0];
NSLog (@ "%@", Nsstringfromcgrect (Cell.frame));
return cell; }-(Cgsize) CollectionView: (Uicollectionview *) CollectionView layout: (uicollectionviewlayout *) collectionviewlayout
Sizeforitematindexpath: (Nsindexpath *) Indexpath {cgfloat CELLW = 100;
CGFloat CELLH = + (Arc4random ()% 80);
[Self.heightarraym addobject:@ (CELLH)];
Return Cgsizemake (CELLW, CELLH);
} @end
<2> the second (Swift implementation) is described below
The effect diagram looks like this:
This implementation is more mature, I encapsulate it into a class. In fact, the main thing is to implement three functions
1 rewrite the Prepare method of the parent class to prepare all cell styles
Extension Waterfalllayout {//Prepare prepares layout styles for all cell override Func prepare () {Super.prepare ()//0. Get it The number of em let ItemCount = collectionview!. Numberofitems (insection:0)//1. Get the number of columns let cols = DataSource? Numberofcolsinwaterfalllayout? (self)?? 2//2. Calculate the width of the item let ITEMW = (collectionview!. Bounds.width-self.sectioninset.left-self.sectioninset.right-self.minimuminteritemspacing * CGFloat ((cols-1)))/CG Float (cols)//3. Compute properties for all item for I in StartIndex. <itemcount {//1. Set each item position related properties Let Indexpath = Indexpath (item:i, section:0)//2. Create a by location Ttributes Property Let Attrs = Uicollectionviewlayoutattributes (Forcellwith:indexpath)//3. Random a height Guar D Let height = DataSource? Waterfalllayout (self, indexpath:indexpath) else {fatalerror ("Please set the data source and implement the corresponding data source method")}//4. Remove the most
The location of the small column var MinH = colheights.min ()! Let index = Colheights.index (Of:minh)! MinH = MinH + height + minimumlinespacing Colheights[index] = MinH//5. Set properties of item Attrs.frame = C Grect (X:self.sectioninset.left + (self.minimuminteritemspacing + itemw) * CGFloat (index), y:minh-height-self.minimum LineSpacing, WIDTH:ITEMW, Height:height) attrsarray.append (ATTRS)}//4. Record Maximum maxh = colheights.
Max ()!
5. Copy startIndex = ItemCount} to StartIndex
2) returns an array that sets the cell style
Override Func layoutattributesforelements (in Rect:cgrect)-> [uicollectionviewlayoutattributes]? {return
Attrsarray
}
3) Return to the current contentsize
Override Var collectionviewcontentsize:cgsize {return
cgsize (width:0, Height:maxh + sectioninset.bottom-minimuml inespacing)
}
Summarize:
In the class that I encapsulate below, just follow my data Proxy source protocol and implement the two methods in my protocol, and pass it to me on the due height (I am here to pass random), optional method, if not implemented, there will be a default value, you can implement this function. The agreement is as follows:
@objc protocol Waterfalllayoutdatasource:class {
func waterfalllayout (_ Layout:waterfalllayout, Indexpath:indexp ATH)-> cgfloat
@objc Optional Func numberofcolsinwaterfalllayout (_ layout:waterfalllayout)-> Int
}
The complete code looks like this:
Code in Viewcontroller.swift:
Import Uikit extension Uicolor {class Func randomcolor ()-> Uicolor {return Uicolor (AR C4random_uniform (256))/255.0, Green:float (Arc4random_uniform (256))/255.0, Blue:float (Arc4random_uniform (256))/ 255.0, alpha:1.0)}} private Let Kwatercellid = "Kwatercellid" class Viewcontroller:uiviewcontroller {var cou Nt:int = override Func Viewdidload () {super.viewdidload ()//1. Set layout let layout = Waterfalllayo UT () layout.minimumlinespacing = ten layout.minimuminteritemspacing = ten Layout.sectioninset = Uiedgeinsets (top : Ten, Left:10, Bottom:10, right:10) Layout.datasource = self//2. Create Uicollectionview let Collectionvie W = Uicollectionview (frame:view.bounds, collectionviewlayout:layout) Collectionview.datasource = Self Collection View.register (uicollectionviewcell.self, Forcellwithreuseidentifier:kwatercellid) View.addSubview (CollectionView )}} Extension ViewcontrolLer:uicollectionviewdatasource {Func CollectionView (_ Collectionview:uicollectionview, NumberOfItemsInSection secti On:int)-> Int {return count} Func CollectionView (_ Collectionview:uicollectionview, Cellforitemat index Path:indexpath)-> Uicollectionviewcell {Let cell = Collectionview.dequeuereusablecell (withreuseidentifier:kwate
Rcellid, For:indexpath) Cell.backgroundcolor = Uicolor.randomcolor () if Indexpath.item = = count-1 { Count = Collectionview.reloaddata ()} return cell}} extension Viewcontroller:wa Terfalllayoutdatasource {func Waterfalllayout (_ Layout:waterfalllayout, Indexpath:indexpath)-> CGFloat {Retu RN CGFloat (Arc4random_uniform +)} func Numberofcolsinwaterfalllayout (_ layout:waterfalllayout)-> Int
{return 3}}
The
Encapsulates the Waterfalllayout.swift code in the custom layout as follows:
Import Uikit @objc protocol Waterfalllayoutdatasource:class {func waterfalllayout (_ Layout:waterfalllayout, index
Path:indexpath)-> cgfloat @objc Optional Func numberofcolsinwaterfalllayout (_ layout:waterfalllayout)-> Int Class Waterfalllayout:uicollectionviewflowlayout {//MARK: Externally provided attribute weak Var Datasource:waterfalllayoutdatasou
Rce? MARK: Private properties Fileprivate lazy var attrsarray: [Uicollectionviewlayoutattributes] = [Uicollectionviewlayoutattributes] ( ) fileprivate var totalheight:cgfloat = 0 Fileprivate lazy var colheights: [CGFloat] = {let cols = Self.dat Asource? Numberofcolsinwaterfalllayout? (self)?? 2 var colheights = Array (Repeating:self.sectionInset.top, Count:cols) return colheights} () fileprivate var maxh:cgfloat = 0 fileprivate var startIndex = 0} extension waterfalllayout {//Prepare prepare layout style for all cell override F UNC prepare () {Super.prepare ()//0. Get the number of item let ItemCount = Collectionview!. Numberofitems (insection:0)//1. Get the number of columns let cols = DataSource? Numberofcolsinwaterfalllayout? (self)?? 2//2. Calculate the width of the item let ITEMW = (collectionview!. Bounds.width-self.sectioninset.left-self.sectioninset.right-self.minimuminteritemspacing * CGFloat ((cols-1)))/CG Float (cols)//3. Compute properties for all item for I in StartIndex. <itemcount {//1. Set each item position related properties Let Indexpath = Indexpath (item:i, section:0)//2. Create a by location Ttributes Property Let Attrs = Uicollectionviewlayoutattributes (Forcellwith:indexpath)//3. Random a height Guar D Let height = DataSource? Waterfalllayout (self, indexpath:indexpath) else {fatalerror ("Please set the data source and implement the corresponding data source method")}//4. Remove the most
The location of the small column var MinH = colheights.min ()!
Let index = Colheights.index (OF:MINH)! MinH = MinH + height + minimumlinespacing Colheights[index] = MinH//5. Set properties of item Attrs.frame = C Grect (x:self.sectioninsEt.left + (self.minimuminteritemspacing + itemw) * CGFloat (index), y:minh-height-self.minimumlinespacing, Width:item
W, Height:height) attrsarray.append (ATTRS)}//4. Record maximum Value maxh = Colheights.max ()! 5. StartIndex startIndex = itemCount}} extension waterfalllayout {override Func Layoutattributesforelem Ents (in Rect:cgrect)-> [uicollectionviewlayoutattributes]? {return Attrsarray} override var collectionviewcontentsize:cgsize {return cgsize (width:0, Height:maxh
+ sectioninset.bottom-minimumlinespacing)}}
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.