iOS Custom TableView With Images and Checkmarks

Filed Under: iOS

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.

iOS Custom TableView Project Structure

iOS custom tableview, ios tableview

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

  1. Adding a TableView and setting its constraints.

    ios custom tableview example

  2. Adding a TableViewCell and an ImageView in the cell and setting its constraints.

  3. Adding a label between the ImageView and the AccessoryType – checkmark and setting its constraints.

  4. 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.
        }
    
    
    }
    
  5. 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

Comments

  1. SwifterMan says:

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

  2. Prasad says:

    Cells are automatically showing checkmark after scrolling

  3. saiteja says:

    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.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages