Include UICollectionView in UITableViewCell

Tram Ho

Putting CollectionVIew inside the table view cell is a popular design in current popular Apps, such as Sportify, Netflix, App Store or even Facebook, etc.
This design is suitable when we want to display a list of items vertically (table view), but each item contains a list of child items that can be browsed horizontally (collection view). Let’s look at the example of AppStore, we have many items like “What We’re Playing”, “New Games We Love”, “Top Apple Arcade Games”, … In each item, we include a list of corresponding games. , drag horizontally

Where we have a few horizontal lists, putting in a Scroll View containing many Collection Views and setting Data for them respectively is also a solution. This method is simple, but try to make the case that our items are updated regularly, and can contain 10, even 20 Collection View, this approach is not reasonable. Introducing a Table View, in which each Cell contains a Collection View, also helps to increase reuse, as well as maintainability during product development.

Before getting into the main part, take a look at the composition to get a handle on what we’re going to do

  • Collection View Cells are in Collection View (Of course)
  • Collection View resides in a Table View Cell
  • Table View Cell is in Table View (Another natural thing)

The only thing unfamiliar here is the inclusion of Collection View inside the Table View Cell. They are all View, so turning this into a Subview of is possible. The problem is how to set the DataSource for each CollectionView

There are 2 approaches to this problem

  • The information needed for Collection View Data Source will be stored and set in Table View Cell. This may sound simple, but it conflicts with the thought of MVC, when the Views directly access to Models.
  • The second way is that we will set the CollectionViewDataSource at the Controller itself and find a way to distinguish the CollectionViews to set properly. In today’s lesson, we will solve the problem this way

Controller will be datasource, delegate for both table view and all collection view

If we only have 1 collection view in a controller, the processing becomes familiar and simple. The problem is that we only have one controller but contain many collection views. We will have to have a way to distinguish them, which collection view is in the first row (in table view), which collection view is in the second row, … Because table view in our case has only 1 section, so to separate Unlike collection view, we only need to determine which row of the table view contains it. UIView provides us with a very useful attribute, which is the tag. The concept of tag is defined as follows

We will use the tag to mark the collection view to see which row it is stored in. In this article, I will go into specific ways of implementing the code for the case you have Table View Cell and Collection View Cell custom (instead of the default Cell). . So we will have 2 Xib files, 1 Table View Cell Class and 1 Collection View Cell Class, 1 View Controller Class and 1 Storyboard.

First, create a new project, drag a Table view onto the Main.Storyboard and layout for it

Table View mapping into ViewController

Create MainTableViewCell.swift file with XIB to customize TableViewCell

In this example, I will just drag into a CollectionView and layout it to fill the Cell

Create ColorCell.swift file with XIB to customize for UICollectionViewCell. You can create custom cells any way you want. Here I will drag into a symbolic View and fill it with Cell

Open the ColorCell.swift file. Map the newly dragged view and add the setContentForCell () function. Here I will pass a UIColor and set the color for that view

There are still familiar actions, right? Switch to MainTableCell.swift and edit a bit. There are some things we need to consider here

  • Create a setUpCollectionView function to register nib for collectionView and call it in awakeFromNib () (Don’t forget this function if you don’t want the program to crash)
  • Pay attention to the setCollectionViewDataSourceDelegate function. This function will set Datasource, Delegate for collection View and tag the corresponding with row Number. This writing may be a bit strange, this is Protocol Composition, you can read more in Swift Doc
  • At the end of this function is the reloadData () function. The reason is because when resetting dataSource for collection View, the reloadData () function should be called. Each time Collection View appears we will reset the Data Source for it. But UIKit seems to understand that we have setDataSource for this collection view before, so when it is called, it doesn’t call reloadData () anymore -> The data is wrong. So we have to add this function at the end of the code

Now we will set up TableView and CollectionView in ViewController. Here I will use the generateRandomData () function to generate a [[UIColor]]. We have a tableView, the data for 1 cell will be a [UIColor]. And each element of that [UIColor] will be used to set data for each collectionViewCell inside that tableViewCell. You can refer to that function here
https://github.com/ashfurrow/Collection-View-in-a-Table-View-Cell/blob/master/Table View in a Collection View / Helpers.swift

We need some basic functions to set up TableView

Now we need to set Datasource, Delegate and rowNumber for collectionview. There are several functions in UITableViewDelegate that can be used in this case. Here we want the Datasource and delegate to be reset when Cell is about to appear, so I’ll put it in the willDisplayCell function.

We will see an error because we are declaring the collection to use self for datasource and delegate, but ViewController has not conformed to these two protocols. But don’t worry, we’ll declare it now

Of the two set up datasource functions for collectionview, we all use tags to identify the data that will be used on the collectionview, thereby calculating the number of rows needed.

Here I will call the heightForRowAt function in UITableViewDelegate to set the height for tableviewcell.

Build and Run Project we get the following results:

It looks pretty good, doesn’t it. But if you interact for a while you will see a little problem because the cells are reuse. We want to “remember” the location the user scrolled to at each collectionview. To do so, open the MainTableViewCell.swift file and add the

collectionViewOffSet property. This value is used to return the position the user is scrolling to.

Going back to ViewController, we need to create a variable to store the offset of the collectionview. Here I will use a dictionary

Additional UITableViewDelegate

  • When the Cell is about to appear, we will reattach the Offset to it according to the saved value. Where the offset of that collectionview has not been recorded (Cell has just been initialized), we will set it offSet to 0 (ie collectionview will be scrolled to the first position)
  • The didEndDisplaying cell function is called when the cell is no longer on screen. Now we will record its offet by resetting the storedOffsets at the corresponding index

Build and Rerun Project, we have obtained a complete product.

Reference source: https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/

Share the news now

Source : Viblo