How to realize the waterfall flow effect in IOS _ios

Source: Internet
Author: User

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

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

---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
    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

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;


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.

Related Article

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: 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.