Reputation: 2187
How do you programmatically set a UIView to be in the center of its superview using Auto Layout?
UIButton* viewObj = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[viewObj setTranslatesAutoresizingMaskIntoConstraints:NO];
[viewObj setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:viewObj];
NSLayoutConstraint* cn = [NSLayoutConstraint constraintWithItem:viewObj
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
[self.view addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:viewObj
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0];
[self.view addConstraint:cn];
The above code works for me for UIButton, but I'm having trouble replacing the first line with something that works for a UIView.
I've tried
UIView* viewObj = [UIView alloc] initWithFrame:CGRectZero];
but the view does not show up in simulator.
Any suggestions?
Thanks!
Upvotes: 27
Views: 29011
Reputation: 92409
UIButton
, UIImageView
, UIlabel
and UITextField
can automatically set their size according to their content properties. The width and height of a UIImageView
are set by the UIImage
it may contain. The size of a UILabel
will depend on its text. The width and height of a UIButton
are defined by the title and the image it has (you can learn more about it with Intrinsic Content Size).
Therefore, when you want to center a UIButton
, a UILabel
, a UITextField
or a UIImageView
inside a UIView
with auto layout, in almost all cases you don't have to create constraints for their width and height. You simply need to set horizontal and vertical constraints for them.
However, with auto layout, a UIView
that has no subviews can't rely on anything to set its size unless you provide it some arbitrary width and height constraints. And according to your needs, you can solve this in 3 different ways.
Here, we set the width and height of our UIView
directly as auto layout constraints:
override func viewDidLoad() {
super.viewDidLoad()
let newView = UIView()
newView.backgroundColor = .redColor()
newView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(newView)
// Auto layout code using anchors (iOS9+)
let horizontalConstraint = newView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor)
let verticalConstraint = newView.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor)
let widthConstraint = newView.widthAnchor.constraintEqualToAnchor(nil, constant: 100)
let heightConstraint = newView.heightAnchor.constraintEqualToAnchor(nil, constant: 100)
NSLayoutConstraint.activateConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
}
Here, we initialize our UIView
with its width and height, make its center and its superview's center equal and create some autoresizing masks. Then, we ask UIKit to translate those autoresizing masks into auto layout constraints:
override func viewDidLoad() {
super.viewDidLoad()
let newView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
newView.backgroundColor = .redColor()
newView.center = CGPointMake(view.bounds.midX, view.bounds.midY)
newView.autoresizingMask = [.FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleTopMargin, .FlexibleBottomMargin]
newView.translatesAutoresizingMaskIntoConstraints = true // default is true
view.addSubview(newView)
}
Here, we create a subclass of UIView
and override its intrinsicContentSize()
method (declaration) so that it returns the desired size:
import UIKit
class CustomView: UIView {
override func intrinsicContentSize() -> CGSize {
return CGSize(width: 100, height: 100)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let newView = CustomView()
newView.backgroundColor = .redColor()
newView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(newView)
let horizontalConstraint = NSLayoutConstraint(item: newView,
attribute: .CenterX,
relatedBy: .Equal,
toItem: view,
attribute: .CenterX,
multiplier: 1,
constant: 0)
view.addConstraint(horizontalConstraint)
let verticalConstraint = NSLayoutConstraint(item: newView,
attribute: .CenterY,
relatedBy: .Equal,
toItem: view,
attribute: .CenterY,
multiplier: 1,
constant: 0)
view.addConstraint(verticalConstraint)
}
}
Upvotes: 9
Reputation: 4931
Since you asked this question in the context of using Auto Layout, the issue here is that a UIButton has an intrinsic size (communicated through the intrinsicContentSize method) that provides Auto Layout with information about width and height, but a UIView normally does not. So you need to add more constraints related to width and height.
If you want your UIView to be a set size (say, 200x200), you could add these lines:
cn = [NSLayoutConstraint constraintWithItem:viewObj
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:200];
[viewObj addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:viewObj
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:200];
[viewObj addConstraint: cn];
Note that the toItem:
argument is nil
and the second attribute is NSLayoutAttributeNotAnAttribute
, because you aren't specifying the width and height relative to anything else. If you want the subview's height and width to be relative to the superview (say, 0.5), you could do this:
cn = [NSLayoutConstraint constraintWithItem:viewObj
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:0.5
constant:0];
[self.view addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:viewObj
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:0];
[self.view addConstraint: cn];
Upvotes: 21