The first is the effect demo
Features: You can set the total number of columns for the waterfall flow (the effect is 2 columns)
Although the iphone's system album does not use this layout effect, waterfall flow is still a very common way of layout!!! Here's a detailed description of how to implement this layout.
The first class to use is Uicollectionview
What we're going to do is customize Uicollectionviewcell and Uicollectionviewlayout.
1, the Custom Uicollectionviewcell class, only needs one uiimageview, frame fills the entire cell.
2, the focus is the custom uicollectionviewlayout, note must inherit in Uicollectionviewlayout, do not inherit from Uicolletionviewflowlayout.
3, also need to calculate the picture height.
Why do you want to customize Uicollectionviewlayout?
Because we need to set the height and position of each item, notice here is the position, we will really set the position of each item believe me!!! Custom Uicollectionviewlayout must override three protocol methods, as described later.
Why do you want to calculate the height of a picture?
Because the picture width is fixed, therefore needs to calculate the height according to the picture proportion, causes the picture and so on proportional display. The advantage is that MOM no longer has to worry about my pictures being stretched out of shape ... and also need to use the height of the picture to calculate the entire CollectionView contentsize ... Finish the call!!!
The main course is here!!!
The following are included in the custom Customcollectionviewlayout class
Custom Uicollectionviewlayout The three protocol methods that must be overridden
//1. Calculates the size and position of each item
-(void) preparelayout;
2. Returns the layout properties for each item
-(Nullable nsarray<__kindof uicollectionviewlayoutattributes *> *) Layoutattributesforelementsinrect: (cgrect) rect;
3. Return the total height of the CollectionView
-(cgsize) collectionviewcontentsize;
You can see that the third method uses nullability and generics, and the system's approach adds new iOS 9 features.
Through the top three method names we can get a general idea of what needs to be done. Say the second method, you need to return an array that holds the Layout property (Uicollectionviewlayoutattributes) object. Then we need to write an array of attributes ( Attributesarray), puts the layout attributes into this property array and returns.
What else do you need? A friend who has read the beginning of the article should have noticed that the number of columns that set the Cascade stream must certainly have a property (NumberOfColumns) to represent the number of columns.
Note that because you want to set the number of columns externally, this property needs to be written in the. h file of the custom class.
In addition, for convenience, define an attribute (Itemwidth) to represent the width of the item
Define an attribute (Contentheight) to represent the height of the contenview of the entire CollectionView.
The first is initialization, and there is no problem
-(Instancetype) init {
self = [super init];
if (self) {
_attributesarray = [Nsmutablearray array];
The default value is set to 2 columns
_numberofcolumns = 2;
_contentheight = 0.0f;
_cellmargin = 5.0f;/**< attribute used to denote spacing
/} return
self;
}
Then the getter method, which requires only the point syntax to get the value of the itemwidth (because it is fixed)
-(CGFloat) itemwidth {
//all margins and. Two columns have three margins, three columns have four margins, the logic is strong is good ...
CGFloat Allmargin = (_numberofcolumns + 1) * _cellmargin;
The total width after removing the boundary
cgfloat nomarginwidth = cgrectgetwidth (self.collectionView.bounds)-allmargin;
The total width of the out margin divided by the number of columns gets the width of each column (i.e. itemwidth) return
nomarginwidth/_numberofcolumns;
}
---is the next difficulty---
The first method that
must override
-(void) Preparelayout {//defines the column with the lowest height of the variable record, which is initially the smallest in the No. 0 column. #pragma mark-note this is from 0.!!!
Nsinteger shortestcolumn = 0;
#pragma mark-Note that this is from the beginning of the 0 AH!!!
Stores the total height of each column. Because the column height of the added picture changes, you need to define an array to record the total height of the column.
Nsmutablearray *columnheightarray = [Nsmutablearray array];
Set the initial height of the column to the height of the margin, no problem!!! for (int i = 0; i < _numberofcolumns i++) {//All column initial height is set to cell spacing [Columnheightarray addobject:@ (_cellmargin)]
;
(int i = 0; i < [Self.collectionview numberofitemsinsection:0]; i++) in the No. 0 area of CollectionView
Need to use this thing, get it ahead of time.
Nsindexpath *indexpath = [Nsindexpath indexpathforitem:i insection:0]; To create the layout Property object that the system needs, look at the arguments at the back to know that this is the layout property of each item uicollectionviewlayoutattributes *layoutattributes = [
Uicollectionviewlayoutattributes Layoutattributesforcellwithindexpath:indexpath];
Put the layout attributes into an array, which is, of course, an array of layout properties defined at the outset [_attributesarray addobject:layoutattributes]; Sets the position of each item (x, y, width, height)//The starting position of the horizontal axis #pragma mark-for example, a total of two columns, now put a picture up, need to put the heightThe smallest column.
#pragma mark-assuming the No. 0 column is the shortest, then the X coordinate of the item begins with a margin width. #pragma mark-(Itemwidth + cellmargin) is a whole cgfloat x = (self.itemwidth + _cellmargin) * Shortestcolumn + _cellmargin
; The ordinate is the height of the smallest column in the total height array #pragma mark-pictures are always added in the height of the smallest column cgfloat y = [Columnheightarray[column] floatvalue];/**< Note class
Type conversion//width Nothing to say cgfloat width = self.itemwidth; #pragma mark-Here's a protocol for a custom class that gets the height of the picture by protocol, and the timing is when you need the item height #pragma mark-passes the item's width to the agent (Viewcontroller), VC calculates the height and returns the height to the custom class #pragma mark-that is, ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓cgfloat height = [Self.del
Egate CollectionView:self.collectionView layout:self Width:self.itemWidth
Heightforitematindexpath:indexpath];
Finished, set the location of the item information, nothing to say Layoutattributes.frame = CGRectMake (x, y, width, height); Top waste half a day to put an item up, the total height of the array is not to update the data columnheightarray[shortestcolumn] = @ ([Columnheightarray[shortestcolumn] Floatvalue] + height + _cellmargin); The height of the entire content, by comparing to get a larger value as the height of the entire content self.contentheight = MAX (Self.contentheight, [Columnheightarray[shortestcolumn]
Floatvalue]); Just put an item up, then at this moment which column of the height is relatively low for (int i = 0; i < _numberofcolumns; i++) {//The height of the column (just add Item) CG
Float currentheight = [Columnheightarray[shortestcolumn] floatvalue];
Remove the column height cgfloat = [columnheightarray[i] floatvalue] in column I;
if (Currentheight > height) {//Column I height (height) is lowest, the lowest height column (shortestcolumn) is of course the column I shortestcolumn = i; }}//thinking about using only the top code will cause problems//not affect the mood, please do not panic ...//Hint: This method will be called multiple times, array}
---the difficulty is over---
No understanding of friends please focus on the above difficult methods.
The second method that must be overridden
2. Returns the layout properties corresponding to each item
-(nsarray<uicollectionviewlayoutattributes *> *) Layoutattributesforelementsinrect: (cgrect) rect {return
_attributesarray;
}
A third method that must be overridden
3. Returns the scrolling range of the CollectionView
-(cgsize) collectionviewcontentsize {return
cgsizemake (0, _contentheight);
}
Viewcontroller There is nothing to say about the way in which CollectionView is created and negotiated.
Look at the creation of the custom class Customcollectionviewlayout and the assignment of the property:
Customcollectionviewlayout *layout = [[Customcollectionviewlayout alloc] init];
Layout.numberofcolumns = 2;/**< Sets the number of waterfalls in Viewcontroller, 2 columns or 3 as the best * *
layout.delegate = self;/**< Specify VC as the agent for the method of calculating the height agreement * *
Then look at the implementation part of the Protocol method (implemented in VIEWCONTROLLER.M)
-(CGFloat) CollectionView: (Uicollectionview *) CollectionView
layout: (Uicollectionviewlayout *) Collectionviewlayout
Width: (cgfloat) Width
heightforitematindexpath: (nonnull nsindexpath *) Indexpath {
uiimage *image = _imagesarray[indexpath.row];
Set a suitable rectangle according to the width of the pass, and the height is set to Cgfloat_max to calculate the height of the width
cgrect boundingrect = CGRectMake (0, 0, width, cgfloat_max);
By using the system function to get the final rectangle, you need to introduce a header file
//#import <AVFoundation/AVFoundation.h>
cgrect imagecurrentrect = Avmakerectwithaspectratioinsiderect (Image.size, boundingrect);
return imageCurrentRect.size.height;
}
Summarize
Here, the realization of the waterfall stream in iOS is over, interested friends can do their own try, I hope this article on the development of iOS help.