Flow Layout Grid List View Collectionview Ios Swift

Change the flow layout of a collectionView – from grid to list view

Create your own flow layout

I’ve always wanted to do this solution that I’m about to show you guys now, and the time is finally here.

I’m pretty sure you’ve seen this before in other apps. We are going to do create 2 separate UICollectionViewFlowLayouts and transition from one to another. A typical example of this is when you have a grid layout and you wish to display your items in a list view (similar to a normal UITableView but with UICollectionView). A flow layout can be hard to learn at first, but ones you get used to it, it is brilliant.

This is how it will look like once we are finished.

UICollectionView flow layout change

What we need?

We basically need a UICollectionView and 2 separate UICollectionViewFlowLayouts. One layout will be responsible for displaying the grid view layout, and the other one for the list view.

Start with our project setup

Let’s start with the basics. Create a UIViewController and add an UICollectionView inside it. Nothing fancy.

We also need to implement the UICollectionViewDataSource protocol to be able to tell the collectionView what objects to display and how many.

Next up, let’s setup the UI and add a custom UICollectionViewCell so we can display our items.

Creating the UI

As you can see in the design, we have an upper view section with a user icon, a title label, a label to display how many items are in the user’s collection, and 2 buttons for switching layouts.

Let’s start by adding the upper header section.

First add a new UIView to the viewController, make it 130px tall and place it to the top of the view.

header view layout in interface builder collectionView grid list flow layout

Add the UICollectionView to the ViewController and place a UIImageView inside the cell.

After that add the other elements to the header view, such as the two labels and the profile imageView.

The imageView should be placed 30pt from the left margin, have a size of 66×66 and center vertically inside the headerView.

The labels are a bit tricky. As you can tell in the design, those labels should be vertically centered to the profile image. In this project we are also supporting iOS 8 so Stack views are out.

Learn how to align the 2 labels vertically centered to the Profile image

The trick is to use a transparent view that will hold the labels as its subviews and this view will be vertically centered to the profile image.

uicollectionview grid list view layout flow ios swift

Align your helper view as seen above or the way you like it.

Obviously, it will not solve the whole layout issue, you will need additional Auto Layout constraints for the subview labels as well.

Below you’ll see the layout setups for those labels. The big secret is that you don’t set a height constraint to any of the labels. Just define the top, left, right and bottom constraints, and Auto Layout will resize your parent view according to the labels’ contents. So it doesn’t matter if the title label contains a nickname with few characters or a pretty long name.

profile-label-collectionview-grid-list-flow-layout-ios-swift

Add the following constraints to the profile title label.

profile label collectionview grid list flow layout ios swift

Add the above contraints to your detail label.

Than add the two buttons.

Simply add it below the headerView and add the following constraints to them:

Equal to width (of the superview/ViewController’s view): 1/2

Left: 0pt

Top: 0pt (to the headerView)

Height: 48pt

 

For the list view button:

Right: 0pt

Left: 0pt (to the grid view)

Top: 0pt (to the headerView)

Height: 48pt

button auto layout collectionview ios layout flow grid list

Constraints for the grid button.

Once we are done with the UI part, let’s add some outlets and connect them in Interface Builder.

Let’s setup the initial layout and the datasource for the app. In this example we are just using a simple object that contains the name of the image.

Call these methods in viewDidLoad to initialise our collectionView with the gridFlowLayout.

The flow layout

We will need 2 separate UICollectionViewFlowLayout objects to be able to specify the grid and list layouts.

Start with the grid view layout:

 

Note that we define each UICollectionViewCell’s¬†width in the itemWidth function, this is also the place where you can tell your collectionView how many columns to display. In this we’ll display 2 columns for the grid layout.

 

List layout

The list layout’s setup is similar to the grid’s. The only difference is that in the itemWidth() function, we’ll use the collectionView’s width.

Changing between grid and list layouts

With a press of a button, you can change from one layout to another. It is simple as that. First you need to invalidate the layout than set the new layout to be the current one.

flow layout ios swift collectionview grid view

If you like these tutorials, please give it a like or share on Twitter, Facebook. Thanks.

P.S.: Make it work when you rotate the device

If you are supporting landscape modes, than you would probably want to add this line to your viewController.

It will invalidate the current layout and forces it to recalculate its itemsize.

  • Nikolay Dementiev

    Where can I see a link to download this project?

  • Jack Nguyen

    Awesome tutorial Zapp! I have a question that could we do the same but with different .xib cell (like instagram)? Thank you!

    • http://zappdesigntemplates.com ZappDev

      Sure, in the cellForRowAtIndexPath method, you could just use the “isGridFlowLayoutUsed” boolean, and return the proper cell according to your needs.

      • Nikolay Dementiev

        Did you mean: “cellForItemAtIndexPath”?

        .. still a question: this function is not called when switching species. how to call it?

        • http://zappdesigntemplates.com ZappDev

          Yes.

          You can use it like so:

          func changeLayoutToGridView() {
          isGridFlowLayoutUsed = true
          collectionView.reloadData()
          UIView.animateWithDuration(0.2) { () -> Void in
          self.collectionView.collectionViewLayout.invalidateLayout()
          self.collectionView.setCollectionViewLayout(self.gridFlowLayout, animated: false)
          }
          }

          ReloadData will trigger cellForItemAtIndexPath where you can use the boolean that says which layout is being used currently to tell your collectionView which cell to use.

          • Nikolay Dementiev

            Thank you so much. it worked.! // My mistake was that I tried to update collection to outside the main stream…

      • Jack Nguyen

        Beautiful!

  • Pingback: New Car Dealerships iOS App Template and Source Code()

  • travelcrumbs

    It really great post. I have a question I want implement like an instagram’s profile page. Instagram has not only images but also has an comment and like buttons and more buttons. I want using your tutorials but when I tapped second button then How do I add like buttons and comments?

  • Patomphong Wongkalasin

    Awesome!

  • Punith Bm

    Great!!… is’t objective C version is available

  • Pingback: From List view to Water flow view and Grid View using collection view flow layouts – ValueStack.io()

  • Nupur Sharma

    Where did you define imageToDisplay??

    • http://zappdesigntemplates.com ZappDev

      In the ViewController, it’s just a simple struct.