I\'ve been looking for a lot of snippets in the net and I still can\'t find the answer to my problem. My question is I have a scrollView(SV) and I want to add a button insid
I needed to cover the superview completely. The other ones wouldn't do that during orientation changes. So I wrote a new one which does - using an arbitrary size multiplier of 20. Feel free to change to your needs. Also note this one in fact makes the subview a lot bigger than the superview which might be different from requirements.
extension UIView {
func coverSuperview() {
guard let superview = self.superview else {
assert(false, "Error! `superview` was nil – call `addSubview(_ view: UIView)` before calling `\(#function)` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
let multiplier = CGFloat(20.0)
NSLayoutConstraint.activate([
self.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: multiplier),
self.widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: multiplier),
self.centerXAnchor.constraint(equalTo: superview.centerXAnchor),
self.centerYAnchor.constraint(equalTo: superview.centerYAnchor),
])
}
}
I'm not sure if this is the most efficient way to do it, but it works..
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.translatesAutoresizingMaskIntoConstraints = NO;
// initialize
[coverForScrolView addSubview:button];
NSLayoutConstraint *width =[NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeWidth
relatedBy:0
toItem:coverForScrolView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
NSLayoutConstraint *height =[NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeHeight
relatedBy:0
toItem:coverForScrolView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0];
NSLayoutConstraint *top = [NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:coverForScrolView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.f];
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:button
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:coverForScrolView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.f];
[coverForScrolView addConstraint:width];
[coverForScrolView addConstraint:height];
[coverForScrolView addConstraint:top];
[coverForScrolView addConstraint:leading];
I've picked the best elements from the other answers:
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.topAnchor.constraint(equalTo: superview.topAnchor),
self.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor),
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor)
])
}
}
You can use it like this, for example in your custom UIView:
let myView = UIView()
myView.backgroundColor = UIColor.red
self.addSubview(myView)
myView.bindFrameToSuperviewBounds()
Here's a more functional approach in Swift 3+ with a precondition instead of a print
(which can perish easily in the console). This one will report programmer errors as failed builds.
Add this extension to your project:
extension UIView {
/// Adds constraints to the superview so that this view has same size and position.
/// Note: This fails the build if the `superview` is `nil` – add it as a subview before calling this.
func bindEdgesToSuperview() {
guard let superview = superview else {
preconditionFailure("`superview` was nil – call `addSubview(view: UIView)` before calling `bindEdgesToSuperview()` to fix this.")
}
translatesAutoresizingMaskIntoConstraints = false
["H:|-0-[subview]-0-|", "V:|-0-[subview]-0-|"].forEach { visualFormat in
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: visualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
}
}
Now simply call it like this:
// after adding as a subview, e.g. `view.addSubview(subview)`
subview.bindEdgesToSuperview()
Note that the above method is already integrated into my HandyUIKit framework which also adds some more handy UI helpers into your project.
If you work a lot with programmatic constraints in your project then I recommend you to checkout SnapKit. It makes working with constraints a lot easier and less error-prone.
Follow the installation instructions in the docs to include SnapKit into your project. Then import it at the top of your Swift file:
import SnapKit
Now you can achieve the same thing with just this:
subview.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
addConstraint
and removeConstraint
methods for UIView are going to be deprecated, so it's worth to use 'constraint creation conveniences':
view.topAnchor.constraint(equalTo: superView.topAnchor, constant: 0).isActive = true
view.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: 0).isActive = true
view.leadingAnchor.constraint(equalTo: superView.leadingAnchor, constant: 0).isActive = true
view.trailingAnchor.constraint(equalTo: superView.trailingAnchor, constant: 0).isActive = true