Hi everyone =D
I will show in this article how to use multiple types of cells in your UITableView or UICollectionView.
A lot of developers do that in the wrong way, using sections or rows to present another kind of cell.
This tutorial will be separated on 3 fronts:
- 1 - Create a model
- 2 - Register cells on your controller
- 3 - Organize it on cellForRow
Creating a model
First of all, I create a simple model to populate my table.
public enum VehicleType { | |
case car | |
case moto | |
case bike | |
} | |
public struct Vehicle { | |
public let manufacturer: String | |
public let model: String | |
public let type: VehicleType | |
public let year: Int | |
public let imageName: String | |
init(manufacturer: String, model: String, type: VehicleType, year: Int, imageName: String) { | |
self.manufacturer = manufacturer | |
self.model = model | |
self.type = type | |
self.year = year | |
self.imageName = imageName | |
} | |
} |
The secret of this model is the enum VehicleType. That changes everything!
Creating and register cell on table
After that, I create 3 kinds of cell:
Bike Cell
private func registerCell() { | |
let carCell = UINib(nibName: "CarTableViewCell", bundle: Bundle.main) | |
let motoCell = UINib(nibName: "MotoTableViewCell", bundle: Bundle.main) | |
let bikeCell = UINib(nibName: "BikeTableViewCell", bundle: Bundle.main) | |
tableView.register(carCell, forCellReuseIdentifier: "carCell") | |
tableView.register(motoCell, forCellReuseIdentifier: "motoCell") | |
tableView.register(bikeCell, forCellReuseIdentifier: "bikeCell") | |
} |
And create an array of vehicles:
private func setVehicles() { | |
vehicles = [ | |
Vehicle(manufacturer: "Jeep", model: "Willys", type: .car, year: 1970, imageName: "jeep-willys"), | |
Vehicle(manufacturer: "Harley Davidson", model: "Iron 883", type: .moto, year: 2018, imageName: "harley-davidson-iron883"), | |
Vehicle(manufacturer: "Bianchi", model: "Super Pista", type: .bike, year: 2015, imageName: "bianchi-super-pista"), | |
Vehicle(manufacturer: "Land-Rover", model: "Defender 90", type: .car, year: 1999, imageName: "land-rover-defender90") | |
] | |
tableView.reloadData() | |
} |
Set cell on cellForRow
Ok, we are almost done! What we need to do right now is configure our cellForRow atIndexPath
or itemForRow atIndexPath
.
Write an switch case to determine what kind of cell table will present. Like this example:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let vehicle = vehicles[indexPath.row] | |
switch vehicle.type { | |
case .bike: | |
let cell = tableView.dequeueReusableCell(withIdentifier: "bikeCell") as! BikeTableViewCell | |
cell.set(vehicle: vehicle) | |
return cell | |
case .moto: | |
let cell = tableView.dequeueReusableCell(withIdentifier: "motoCell") as! MotoTableViewCell | |
cell.set(vehicle: vehicle) | |
return cell | |
default: | |
let cell = tableView.dequeueReusableCell(withIdentifier: "carCell") as! CarTableViewCell | |
cell.set(vehicle: vehicle) | |
return cell | |
} | |
} |
But, if you saw, each cell has a different size. Ok, let's do the same thing on heightForRow atIndexPath
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { | |
let vehicle = vehicles[indexPath.row] | |
switch vehicle.type { | |
case .bike: | |
return 180 | |
case .moto: | |
return 120 | |
default: | |
return 243 | |
} | |
} |
And that's it! Simple, beautiful, and very easy!
I don't prepared a beautiful layout on these cells, but, take a look, we have 3 different cells on the same Table or Collection:
Download source code here =D
I hope I have helped everyone looking for this change.
If you would like to extend the discussion, call me on Twitter
Top comments (1)
But all those switch statements are now unnecessay. Each model can now handle this.