I have a UITableViewController that doesn't display any sections if there is nothing to show. I've added a label to indicate to the user that there is nothing to display with this code:
label = UILabel(frame: CGRectMake(20, 20, 250, 100)) label.text = "Nothing to show" self.tableView.addSubview(label)
But now, I want it to be centered Horizontally and Vertically. Normally, I would choose the two options highlighted (plus ones for height and width) in the screenshot:
I've tried the following code to add the constraints but the app crashes with error:
label = UILabel(frame: CGRectMake(20, 20, 250, 100)) label.text = "Nothing to show" let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0) label.addConstraint(xConstraint) label.addConstraint(yConstraint)
error:
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug. 2014-12-23 08:17:36.755 [982:227877] *** Assertion failure in -[UILabel _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /SourceCache/UIKit/UIKit-3318.16.21/NSLayoutConstraint_UIKitAdditions.m:560
The label should always center horizontally and vertically because the app supports rotation of the device.
What am I doing wrong? How do I add these constraints successfully?
Thanks!
To create constraints select the button and click the Align icon in the auto layout menu. A popover menu will appear, check both “Horizontal in container” and “Vertically in container” options to center the button on the screen. Then click the “Add 2 Constraints” button. Run the application.
The relationship between two user interface objects that must be satisfied by the constraint-based layout system.
Update for Swift 3/Swift 4:
As of iOS 8, you can and should activate your constraints by setting their isActive
property to true
. This enables the constraints to add themselves to the proper views. You can activate multiple constraints at once by passing an array containing the constraints to NSLayoutConstraint.activate()
let label = UILabel(frame: CGRect.zero) label.text = "Nothing to show" label.textAlignment = .center label.backgroundColor = .red // Set background color to see if label is centered label.translatesAutoresizingMaskIntoConstraints = false self.tableView.addSubview(label) let widthConstraint = NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 250) let heightConstraint = NSLayoutConstraint(item: label, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100) let xConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: self.tableView, attribute: .centerX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: self.tableView, attribute: .centerY, multiplier: 1, constant: 0) NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])
Better Solution:
Since this question was originally answered, layout anchors were introduced making it much easier to create the constraints. In this example I create the constraints and immediately activate them:
label.widthAnchor.constraint(equalToConstant: 250).isActive = true label.heightAnchor.constraint(equalToConstant: 100).isActive = true label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor).isActive = true label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor).isActive = true
or the same using NSLayoutConstraint.activate()
:
NSLayoutConstraint.activate([ label.widthAnchor.constraint(equalToConstant: 250), label.heightAnchor.constraint(equalToConstant: 100), label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor), label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor) ])
Note: Always add your subviews to the view hierarchy before creating and activating the constraints.
Original Answer:
The constraints make reference to self.tableView
. Since you are adding the label as a subview of self.tableView
, the constraints need to be added to the "common ancestor":
self.tableView.addConstraint(xConstraint) self.tableView.addConstraint(yConstraint)
As @mustafa and @kcstricks pointed out in the comments, you need to set label.translatesAutoresizingMaskIntoConstraints
to false
. When you do this, you also need to specify the width
and height
of the label with constraints because the frame no longer is used. Finally, you also should set the textAlignment
to .Center
so that your text is centered in your label.
var label = UILabel(frame: CGRectZero) label.text = "Nothing to show" label.textAlignment = .Center label.backgroundColor = UIColor.redColor() // Set background color to see if label is centered label.translatesAutoresizingMaskIntoConstraints = false self.tableView.addSubview(label) let widthConstraint = NSLayoutConstraint(item: label, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 250) label.addConstraint(widthConstraint) let heightConstraint = NSLayoutConstraint(item: label, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100) label.addConstraint(heightConstraint) let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0) self.tableView.addConstraint(xConstraint) self.tableView.addConstraint(yConstraint)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With