Skip to content

Instantly share code, notes, and snippets.

@jacobmbarnard
Created September 4, 2018 18:41
Show Gist options
  • Save jacobmbarnard/207d611150e9efabaef6ebf6537e22f8 to your computer and use it in GitHub Desktop.
Save jacobmbarnard/207d611150e9efabaef6ebf6537e22f8 to your computer and use it in GitHub Desktop.
Practical Programmatic Auto Layout for UITableViewCell in Swift 4.1
import UIKit
public class MyAutoLayoutTableViewCell: UITableViewCell {
var myRedLabel: UILabel
var myGreenLabel: UILabel
var myBlueLabel: UILabel
override public init(style: UITableViewCellStyle, reuseIdentifier: String?) {
myRedLabel = UILabel(frame: CGRect.zero)
myGreenLabel = UILabel(frame: CGRect.zero)
myBlueLabel = UILabel(frame: CGRect.zero)
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupContentView()
setupSubviewsForAutoLayout()
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupContentView() {
let width = UIScreen.main.bounds.width
contentView.frame = CGRect(x: 0.0, y: 0.0, width: width, height: 60.0)
}
fileprivate func setupSubviewsForAutoLayout() {
let views: [String: Any] = [
"myRedLabel": myRedLabel,
"myGreenLabel": myGreenLabel,
"myBlueLabel": myBlueLabel
]
setupMyRedLabel(for: views)
setupMyGreenLabel(for: views)
setupMyBlueLabel(for: views)
}
fileprivate func setupMyRedLabel(for views: [String: Any]) {
var constraints: [NSLayoutConstraint] = []
contentView.addSubview(myRedLabel)
myRedLabel.layoutMargins = UIEdgeInsets.zero
myRedLabel.text = "Red Label"
myRedLabel.font = UIFont.boldSystemFont(ofSize: 15.0)
myRedLabel.textColor = .red
myRedLabel.translatesAutoresizingMaskIntoConstraints = false
let myRedLabelHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[myRedLabel]", options: [], metrics: nil, views: views)
let myRedLabelVerticalConstraint = NSLayoutConstraint.constraints( withVisualFormat: "V:|-5-[myRedLabel(==18)]", options:[], metrics: nil, views: views)
constraints += myRedLabelHorizontalConstraint + myRedLabelVerticalConstraint
NSLayoutConstraint.activate(constraints)
}
fileprivate func setupMyGreenLabel(for views: [String: Any]) {
var constraints: [NSLayoutConstraint] = []
contentView.addSubview(myGreenLabel)
myGreenLabel.layoutMargins = UIEdgeInsets.zero
myGreenLabel.text = "Green Label"
myGreenLabel.font = UIFont.boldSystemFont(ofSize: 15.0)
myGreenLabel.textColor = .green
myGreenLabel.translatesAutoresizingMaskIntoConstraints = false
let myGreenLabelHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:[myRedLabel]-8-[myGreenLabel]", options: [], metrics: nil, views: views)
let myGreenLabelVerticalConstraint = NSLayoutConstraint.constraints( withVisualFormat: "V:|-5-[myGreenLabel(==18)]", options:[], metrics: nil, views: views)
constraints += myGreenLabelHorizontalConstraint + myGreenLabelVerticalConstraint
NSLayoutConstraint.activate(constraints)
}
fileprivate func setupMyBlueLabel(for views: [String: Any]) {
var constraints: [NSLayoutConstraint] = []
contentView.addSubview(myBlueLabel)
myBlueLabel.layoutMargins = UIEdgeInsets.zero
myBlueLabel.text = "Blue Label"
myBlueLabel.font = UIFont.boldSystemFont(ofSize: 15.0)
myBlueLabel.textColor = .blue
myBlueLabel.translatesAutoresizingMaskIntoConstraints = false
let myGreenLabelHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[myBlueLabel]", options: [], metrics: nil, views: views)
let myGreenLabelVerticalConstraint = NSLayoutConstraint.constraints( withVisualFormat: "V:[myRedLabel]-5-[myBlueLabel]", options:[], metrics: nil, views: views)
constraints += myGreenLabelHorizontalConstraint + myGreenLabelVerticalConstraint
NSLayoutConstraint.activate(constraints)
}
}
@jacobmbarnard
Copy link
Author

If you merely want to see this cell in action on launch in a new iPhone project, a quick way to do that is:

  1. Create a new Single View application.
  2. Delete the Main storyboard file.
  3. Remove the Main storyboard file designation in the Info.plist.
  4. Change your AppDelegate to look like this:
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let rootMenuViewController = MyTableViewController(style: .grouped)
        window!.rootViewController = rootMenuViewController
        UIApplication.shared.statusBarStyle = .default
        window!.makeKeyAndVisible()
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {}
    func applicationDidEnterBackground(_ application: UIApplication) {}
    func applicationWillEnterForeground(_ application: UIApplication) {}
    func applicationDidBecomeActive(_ application: UIApplication) {}
    func applicationWillTerminate(_ application: UIApplication) {}
}

and make a simple UITableViewController subclass like so:

import UIKit

class MyTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(MyAutoLayoutTableViewCell.self, forCellReuseIdentifier: "MyAutoLayoutTableViewCell")
    }
    
    override public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 5 }
    
    override public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 60.0 }
    
    override public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MyAutoLayoutTableViewCell") as! MyAutoLayoutTableViewCell
        let integerIndex = indexPath.row
        cell.myRedLabel.text = "Red label in row \(integerIndex)"
        cell.myGreenLabel.text = "Green label in row \(integerIndex)"
        cell.myBlueLabel.text = "Blue label in row \(integerIndex)"
        return cell
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

Build and run!

screen shot 2018-09-04 at 2 35 32 pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment