iosswiftuitableviewconstraints

How to add programmatic constraints to a UITableView?


I have a class set up as follows:

class SettingsController: UITableViewController {

I would like to be able to add constraints to the UITableView so that there is equal spacing either side of the table (it is currently a full width table, so a little ugly on iPad).

I have read that I can't add constraints to a UITableViewController, and instead I must add a UIViewController to my class, add a UITableView to that, and then I should be able to add the constraints to the TableView.

I've amended the class and defined the UITableView on the next line. So here are my first two lines now:

class SettingsController: UIViewController {
  var tableView = UITableView()

Further down, I have this code to attach the TableView to the UIView:

override func viewDidLoad() {
    super.viewDidLoad()   
    self.view.addSubview(tableView)
}

The app builds successfully but when trying to access this view, the screen is blank, so I've not been able to attempt the constraints part yet (the screen does display the data correctly if I revert what I've described).

Many of my existing functions within this class reference tableView for passing in the data/setting the number of rows etc, but it seems I've not done something right... is there a piece I'm missing?


Solution

  • Here is a simple example of programmatically creating and adding a table view to a "normal" view:

    //
    //  SettingsController.swift
    //
    //  Created by Don Mag on 7/25/17.
    //
    
    import UIKit
    
    class SettingsController : UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        let tableView : UITableView = {
            let t = UITableView()
            t.translatesAutoresizingMaskIntoConstraints = false
            return t
        }()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // set a background color so we can easily see the table
            self.view.backgroundColor = UIColor.blue
    
            // add the table view to self.view
            self.view.addSubview(tableView)
    
            // constrain the table view to 120-pts on the top,
            //  32-pts on left, right and bottom (just to demonstrate size/position)
    
            tableView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 32.0).isActive = true
            tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 120.0).isActive = true
            tableView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -32.0).isActive = true
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -32.0).isActive = true
    
            // set delegate and datasource
            tableView.delegate = self
            tableView.dataSource = self
    
            // register a defalut cell
            tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        }
    
        // Note: because this is NOT a subclassed UITableViewController, 
        // DataSource and Delegate functions are NOT overridden
    
        // MARK: - Table view data source
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 25
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    
            cell.textLabel?.text = "\(indexPath)"
    
            return cell
        }
    
        // MARK: - Table view delegate
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            // etc
        }
    
    }
    

    You should be able to run this without edits, and get a result along these lines: enter image description here It is a very simple example, so should be pretty easy to see what's going on.

    If you already have your (I'm assuming, complex) Settings UITableViewController class working, it should be pretty straight-forward to follow this skeleton and convert yours to a UIViewController + UITableView-as-subview.

    Alternatively, you can load your existing UITableViewController as a child view controller, and add its view (the tableview) as a subview.