Pretty often I find myself writing these lines of code:
myView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
myView.topAnchor.constraint(equalTo: myView.superview.topAnchor),
myView.bottomAnchor.constraint(equalTo: myView.superview.bottomAnchor),
myView.leadingAnchor.constraint(equalTo: myView.superview.leadingAnchor),
myView.trailingAnchor.constraint(equalTo: myView.superview.trailingAnchor)
])
So I'm thinking to write an extension. Something like this:
extension UIView {
func bindFrameToSuperviewBounds() {
self.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.topAnchor.constraint(equalTo: self.superview.topAnchor),
self.bottomAnchor.constraint(equalTo: self.superview.bottomAnchor),
self.leadingAnchor.constraint(equalTo: self.superview.leadingAnchor),
self.trailingAnchor.constraint(equalTo: self.superview.trailingAnchor)
])
}
}
My questions:
Maybe some built-in function (or technique) like this already exists, I just don't know about it (I've googled a lot, though)
Isn't (in theory) this code equivalent to:
myView.translatesAutoresizingMaskIntoConstraints = true
myView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Why in theory? Because in practice it's definitely not equivalent. This alternative technique didn't ever give me a result I expected to see. The result is pretty much unpredictable.
Answering comments:
Where:
Green (outer) rectangle is a containerView (UIView).
Purple (inner) rectangle is a UIStackView, which I'm inserting.
As you can see, constraint approach works great.
Next one is a result of autoresizing mask approach:
Why there are three pictures?
Because the result is different with every new launch of the application!
These two techniques yield the same behavior:
extension UIView {
func bindFrameToSuperviewBoundsWithConstraints() {
translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
topAnchor.constraint(equalTo: superview!.topAnchor),
bottomAnchor.constraint(equalTo: superview!.bottomAnchor),
leadingAnchor.constraint(equalTo: superview!.leadingAnchor),
trailingAnchor.constraint(equalTo: superview!.trailingAnchor)
])
}
func bindFrameToSuperviewBoundsWithAutoResizingMask() {
translatesAutoresizingMaskIntoConstraints = true
frame = superview!.bounds
autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
}
Consider:
class ViewController: UIViewController {
@IBOutlet weak var containerView: UIView!
weak var timer: Timer?
deinit {
timer?.invalidate()
}
override func viewDidLoad() {
super.viewDidLoad()
containerView.clipsToBounds = false
let blueView = UIView()
blueView.backgroundColor = .blue
containerView.addSubview(blueView)
blueView.bindFrameToSuperviewBoundsWithConstraints()
let redView = UIView()
redView.backgroundColor = .red
containerView.addSubview(redView)
redView.bindFrameToSuperviewBoundsWithAutoResizingMask()
// toggle between the red and blue views
blueView.isHidden = true
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
redView.isHidden = !redView.isHidden
blueView.isHidden = !blueView.isHidden
}
}
}
That yields two alternating subviews, each that uses a different technique, illustrating that their frames are the same:
If you are finding that the autoresizing mask solution is yielding different results than the constraint approach, there must be something else going on.