I would like to add programmatically few constraints while I slide from a bottom new table view, but so far I can not understand what am I doing wrong. In my super view
I have map view
which have to change bottom constraint
to make a space for new tableView
while the button is clicked.
Basically for my table view I need 4 constraints:
All the time I am getting crash:
Impossible to set up layout with view hierarchy unprepared for constraint.
Based on setting constraints from: here
Here is a code:
@IBAction func test(_ sender: UIButton) {
let tableView = UITableView()
tableView.backgroundColor = UIColor.red
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let topConstraint = NSLayoutConstraint(item: tableView, attribute: .top, relatedBy: .equal, toItem: self.mapView, attribute: .bottom, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: tableView, attribute: .bottom, relatedBy: .equal, toItem: self.tabBarController?.tabBar, attribute: .top, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: tableView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: tableView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1, constant: 0)
view.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])
// tableView.addConstraint(NSLayoutConstraint(item: tableView, attribute: .top, relatedBy: .equal, toItem: self.mapView, attribute: .bottom, multiplier: 1, constant: 0))
// tableView.addConstraint(NSLayoutConstraint(item: tableView, attribute: .bottom, relatedBy: .equal, toItem: self.tabBarController?.tabBar, attribute: .top, multiplier: 1, constant: 0))
// tableView.addConstraint(NSLayoutConstraint(item: tableView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1, constant: 0))
// tableView.addConstraint(NSLayoutConstraint(item: tableView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1, constant: 0))
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.5, animations: {
self.mapBottomConstaint.constant = 200
self.centerButtonBottomConstaint.constant = 208
self.view.layoutIfNeeded()
})
}
You are trying to set a constraint to a view that is outside your view hierarchy. Auto Layout system provides layout guides to help you align your views with navigation bars and tab bars.
In your bottom constraint, replace self.tabBarController?.tabBar
with bottomLayoutGuide
.
As a side note, new layout syntax (available on iOS 9+) makes much easier creating programmatic constraints without third party libraries:
let topConstraint = tableView.topAnchor.constraint(equalTo: mapView.bottomAnchor)
let bottomConstraint = tableView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor)
let leadingConstraint = tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor)
let trailingConstraint = tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
More info for creating programmatic constraints here.