In this tutorial, we’ll be developing an iOS Application that contains a custom TableView with cells having a custom layout inclusive of images, label and a checkmark. Let’s create a new SingleView Application project and get on with it.
Table of Contents
iOS Custom TableView Project Structure
The project consists of a ViewController.swift
class file which would hold the class for CustomTableViewCells too. Also, the images that we would be displaying shall be present in the Assets folder.
Building Storyboards for iOS TableView
- Adding a TableView and setting its constraints.
- Adding a TableViewCell and an ImageView in the cell and setting its constraints.
- Adding a label between the ImageView and the AccessoryType – checkmark and setting its constraints.
- The
ViewController.swift
would contain another class CustomCell that implements the UITableViewCell protocol as shown below.import UIKit class CustomCell : UITableViewCell{ } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
- Let’s link these classes with the storyboard.
iOS Custom TableView Example Code
The code for the ViewController.swift
file is given below.
import UIKit
class CustomCell : UITableViewCell{
@IBOutlet var myImage: UIImageView!
@IBOutlet var myText: UILabel!
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet var tableView: UITableView!
var labelData = ["Australia", "Brazil", "Canada","China","Germany","India","Malaysia", "Pakistan", "Russia", "South Africa", "United States of America"]
var imageData = ["Australia", "Brazil", "Canada","China","Germany","India","Malaysia", "Pakistan", "Russia", "SouthAfrica", "UnitedStatesofAmerica"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.dataSource = self
tableView.delegate = self
tableView.tableFooterView = UIView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:CustomCell = self.tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomCell
cell.myText?.text = self.labelData[indexPath.row]
cell.myImage?.image = UIImage(named:self.imageData[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labelData.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
if cell.accessoryType == .checkmark{
cell.accessoryType = .none
}
else{
cell.accessoryType = .checkmark
}
}
}
}
In the above code, we set the label and image from the labelData and imageData arrays respectively.
To check/uncheck a cell, we check the accessoryType
attribute on the cell. If it’s equal to checkmark we toggle it to none and vice versa.
The output for the above application in action is given below.
In case we want to allow single choice selection only we can use the below code:
import UIKit
class CustomCell : UITableViewCell{
@IBOutlet var myImage: UIImageView!
@IBOutlet var myText: UILabel!
//For single choice selection
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
selectionStyle = .none
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet var tableView: UITableView!
var labelData = ["Australia", "Brazil", "Canada","China","Germany","India","Malaysia", "Pakistan", "Russia", "South Africa", "United States of America"]
var imageData = ["Australia", "Brazil", "Canada","China","Germany","India","Malaysia", "Pakistan", "Russia", "SouthAfrica", "UnitedStatesofAmerica"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.dataSource = self
tableView.delegate = self
tableView.tableFooterView = UIView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:CustomCell = self.tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomCell
cell.myText?.text = self.labelData[indexPath.row]
cell.myImage?.image = UIImage(named:self.imageData[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labelData.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// tableView.deselectRow(at: indexPath, animated: true)
//
// if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
// if cell.accessoryType == .checkmark{
// cell.accessoryType = .none
// }
// else{
// cell.accessoryType = .checkmark
// }
// }
//
// }
//For single choice selection
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .none
}
}
In the above code, we override the functions didSelectRowAt
as well as didDeselectRowAt
to allow single choice selection. We can’t use tableView.deselectRow(at: indexPath, animated: true)
to animate the selection anymore since that method is already being overridden. Hence we set the selectionStyle in the customCell as none:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
selectionStyle = .none
}
The output of the above implementation is given below:
This brings an end to this tutorial. You can download the final iOS CustomTableViewWithImagesAndCheckMarks Project from the link below.
Reference: iOS Table View
Hi, thanks for share this.
This is not working well.
When I clicked to checkMark on the first INDEX of tableView, the last index from my tableView has been marked too.
Can u tell me a some tip that’s why it is happened?
Cheers!!
Cells are automatically showing checkmark after scrolling
its not working change the label to this var labelData = [“0″,”1″,”2″,”3″,”4″,”5″,”6″,”7″,”8″,”9″,”10″,”11″,”12″,”13″,”14″,”0″,”1″,”2″,”3″,”4″,”5″,”6″,”7″,”8″,”9″,”10″,”11″,”12″,”13″,”14”]
and just for now comment this in cell for row at index path fro not giving image to tableview “// cell.myImage?.image = UIImage(named:self.imageData[indexPath.row])
”
if you select the cell at the top and scroll the table view, some of the cells at the bottom also getting selected.