Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 801
Chris Avatar asked Dec 10 '22 10:12

Chris


2 Answers

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.

like image 65
DonMag Avatar answered Dec 13 '22 00:12

DonMag


So, it looks like you need to back up a step and not try to somehow embed a a UIViewController inside a TableViewController. The recommendation you mentioned means that your SettingsController should subclass UIViewController and you should add a UITableView to that.

Adding constraints to a UITableView will treat you much nicer than trying to play with a UITableViewController at all.

Edit

You should be able to implement the constraints before you have any data. You'll just see an empty table view, but it will still show rows. Sometimes it's easier to play with constraints if you can see what you're dealing with. When you create your tableView, you can do it with: var tableView = UITableView(frame: self.view) at least to help you get your bearings.

So after you implement the constraints you need, it looks like all you'd be missing is setting the tableView's delegate and dataSource and extending your view controller to implement those methods. Then you should have data, and you can bask in the glory of your hard work.

like image 40
Zig Avatar answered Dec 13 '22 00:12

Zig