The construction of waterfall flow frame

Source: Internet
Author: User

Waterfall flow Everyone should be familiar with, now most of the e-commerce applications are more or less used in the waterfall flow, it can attract the user's eyeball, so that users are not easy to produce visual fatigue, Apple added Uicollectionview control in iOS6, this control can be said to be UITableView upgrade version , through this control we can easily make waterfall flow, the back through their own package can make it into a small framework, more simple to apply to our development later

Recently opened Pinterest welcome everyone concerned, I will not regularly share my iOS development experience click Attention-->melody_zhy

If you want to do a waterfall flow, then you need to customize Collectionviewflowlayout because there is a method in this class that returns the layout properties of all child controls in the CollectionView (the frame and index of the control in the layout properties)

-(nsarray<uicollectionviewlayoutattributes *> *) Layoutattributesforelementsinrect: (cgrect) rect {nsarray  *arr = [super    Layoutattributesforelementsinrect:rect];  for  (uicollectionviewlayoutattributes *attri in   arr) {Attri.frame  = CGRectMake (0 , 0 , Span style= "color: #800080;"    >100 , 300  ); } NSLog ( @ " %@   "  return   arr;}  

This method calculates the layout properties of all the child controls in the CollectionView once, is cached after the calculation, and is not repeated to calculate the size of the cell once it has been computed.

Note: If you want to refresh the data then remember to empty the previous layout properties, otherwise layout errors will occur
// empty the data used to load all layout properties [Self.attrarrm removeallobjects];

Now define a variable array property to store a frame in its own computed layout property, and let the method above return its own defined layout properties

// variable array to hold all layout properties @property (nonatomic, strong) Nsmutablearray *ATTRARRM;

So in which method do we calculate our own defined layout properties?

There's a way .

-(void) preparelayout {//  Preparelayout to call the parent class    [Super Preparelayout];}
when all the child controls in CollectionView are about to be displayed, this method is called to prepare for the layout before the itemsize ... The property also calls this method when the property of the layout changes, and then calls this method to redo the layout before the data is refreshed .

In this method, you can get all the cells in a group by Collectionviewflowlayout's CollectionView numberofiteminsection this method

// get all the cells in a group Nsinteger Cellcount = [Self.collectionview numberofitemsinsection:0];

Create a layout property with a For loop (number of cells in a group), and in the loop you need to calculate the frame for each cell so that the background gives the actual picture size (if you don't, the size you calculate will cause the image to flash)

It is usually scaled when displayed.

calculation of cell widthCell width = (width of content-(number of columns-1) * minimum spacing)/Number of columnswidth of content = width of CollectionView-left margin of group-right spacing
CGFloat contentwidth = self.collectionview.bounds.size.width-self.sectioninset.left-1) * self.minimuminteritemspacing)/Self.columncount;
access to cell heights

When you want to get the cell high, you need to get the height of the model picture by the controller (the height must be a certain proportion to the ITEMW or the picture will be too large height/width * ITEMW;), so we need to make the controller become our agent, The protocols defined in the custom CollectionViewFlowLayout.h file are as follows:

#import <UIKit/UIKit.h>@class  zhycollectionviewflowlayout; @protocol Zhycollectionviewflowlayoutdelegate <NSObject>@required-(cgfloat) Waterfallflowlayoutwithitemheight: (zhycollectionviewflowlayout *) FlowLayout ITEMW: (CGFloat) ItemW CellIndexPath: ( Nsindexpath *) Indexpath; @end
and set the proxy properties as follows:
ID Delegate

Call the proxy method to get the cell's height when calculating the cell height

CGFloat CELLH = [self.  Delegate waterfallflowlayoutwithitemheight:self ITEMW:CELLW Cellindexpath:indexpath];
Why add Indexpath to the proxy method because you want to get the model through IndexpathCalculation of Cellx

When calculating cellx, if through nsinteger col = i% Self.columncount; Get column number

One problem to note:

So each time is in order to arrange the picture, then if the size of the picture is uneven and special short and very long, unfortunately, is long in a column of short and all in a column this will cause the aesthetics will be very poor, then how to solve this problem, we can let each line added, The next line adds the first one on the top of the line with the shortest height. The answer, of course, is yes-_-!

At this point we need to define a variable dictionary attribute to store the height of each column, using the column number as the key of the dictionary

// used to record the maximum height of each column @property (nonatomic, strong) Nsmutabledictionary *coldict;
A default height of the dictionary for each column's height in the Preparelayout method
 for 0; i< has several columns; i++) {        *str = [NSString stringWithFormat:@ "%ld", I];         = @ (self.sectionInset.top);    }
How to get the shortest column number
-(NSString *) mincol {    @ "0";    [self.coldict enumeratekeysandobjectsusingblock:^ (ID  ID  _nonnull obj, BOOL * _ Nonnull stop) {        if ([obj Floatvalue] < [Self.coldict[min] floatvalue]) {            = key;        }    }];     return min;}
So the column number is
Nsinteger col = [[self mincol] integervalue];
CELLX is:
CGFloat cellx = Self.sectionInset.left + (CELLW + self.minimuminteritemspacing) * COL;
Calculation of celly

Calculate celly

// use the column number as the key of the dictionary NSString *colstr = [NSString stringWithFormat:@ "%ld"= [Self.coldict[colstr] Floatvalue]; // the height of each column is accumulated self.coldict[colstr] = @ (celly + cellh + self.minimumlinespacing);

So we're done with each cell's x,y,w,h, and we're going to set the layout properties of the frame

// set properties of frameattr.frame = CGRectMake (Cellx, celly, CELLW, CELLH);
At the same time, we also add a layout property to the tail view, the code is as follows
//Create layout properties for the trailer view//Create Footerview IndexNsindexpath *indexpath = [Nsindexpath indexpathforitem:0Insection:0]; //must be an extra layoutattributesforsupplementaryviewofkind.Uicollectionviewlayoutattributes *footerattr =[uicollectionviewlayoutattributes Layoutattributesforsupplementaryviewofkind:    Uicollectionelementkindsectionfooter Withindexpath:indexpath]; Footerattr.frame= CGRectMake (0, [Self.coldict[self.maxcol] floatvalue]-self.minimumlinespacing, Self.collectionView.bounds.size.width, -); [Self.attrarrm addobject:footerattr];
The highest column is used here, because the tail view is placed at the bottom of the cell, and the highest column index is obtained by:
// The column number used to remove the highest column -(NSString *) maxcol {    @ "0";    [self.coldict enumeratekeysandobjectsusingblock:^ (ID  ID  _nonnull obj, BOOL * _nonnull stop) {        if ([obj floatvalue] > [Self.coldict[maxcol] floatvalue]) {            = key;        }    }];     return Maxcol;}
Finally, we return the layout property by the method described above
-(nsarray<uicollectionviewlayoutattributes *> *) Layoutattributesforelementsinrect: (CGRect) rect {     return  self.attrarrm;}
When customizing layout properties, also pay attention to returning the actual contentsize, the code is as follows:
- (cgsize) collectionviewcontentsize {    return cgsizemake (0, [self.coldict[ Self.maxcol] Floatvalue] + self.footerReferenceSize.height- self.minimumlinespacing);}

This is basically done, but if I want to make this waterfall flow layout a simple framework, I need to implement some initialization methods in a simple way.

The CollectionViewFlowLayout.h also defines a row with several cell properties, which can be set when the controller references the class

@property (Assign, nonatomic) Nsinteger ColumnCount;

Provides some initialization methods to make it default that there are 3 cells in a row, cell spacing and line spacing is 10, padding is top, footerreferencesize, headerreferencesize are 50,50

-(instancetype) init{ Self=[Super Init]; if(self) {self.columncount=3; Self.minimuminteritemspacing=Ten; Self.minimumlinespacing=Ten; Self.footerreferencesize= Cgsizemake ( -, -); Self.headerreferencesize= Cgsizemake ( -, -); Self.sectioninset= Uiedgeinsetsmake ( -,0,0,0); }    returnSelf ;}
-(Instancetype) Initwithcoder: (Nscoder *) adecoder{ Self=[Super Initwithcoder:adecoder]; if(self) {self.columncount=3; Self.minimuminteritemspacing=Ten; Self.minimumlinespacing=Ten; Self.footerreferencesize= Cgsizemake ( -, -); Self.headerreferencesize= Cgsizemake ( -, -); Self.sectioninset= Uiedgeinsetsmake ( -,0,0,0); }    returnSelf ;}

So our simple waterfall flow frame is built successfully.

The construction of waterfall flow frame

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.