i have been looking for a simple way to make a constraint equal to it's superview margin(s) and have been doing the following which bugs me:
view.snp.makeConstraing { (make) in
make.leading.equalToSuperview().offset(layoutMargins.left)
make.trailing.equalToSuperview().offset(-layoutMargins.right)
make.top.equalToSuperview().offset(layoutMargins.top)
make.bottom.equalToSuperview().offset(-layoutMargins.bottom)
}
This obviously does not work:
view.snp.makeConstraints { (make) in
make.edges.equalToSuperview().offset(layoutMargins)
}
And i didn't want to explicitly set it to the superviews margins because sometimes you forget to change the things here:
view.snp.makeConstraints { (make) in
make.edges.equalTo(view.margins)
}
I am suggesting you to add something like the following extension:
public extension ConstraintMakerRelatable {
private var relatedConstraintItem: ConstraintItem {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.")
}
var attributes: ConstraintAttributes = .none
if self.description.attributes.contains(.left) { attributes += .leftMargin }
if self.description.attributes.contains(.right) { attributes += .rightMargin }
if self.description.attributes.contains(.top) { attributes += .topMargin }
if self.description.attributes.contains(.bottom) { attributes += .bottomMargin }
if self.description.attributes.contains(.edges) { attributes += .margins }
if self.description.attributes.contains(.leading) { attributes += .leadingMargin }
if self.description.attributes.contains(.trailing) { attributes += .trailingMargin }
if self.description.attributes.contains(.centerX) { attributes += .centerXWithinMargins }
if self.description.attributes.contains(.centerY) { attributes += .centerYWithinMargins }
if self.description.attributes.contains(.center) { attributes += .centerWithinMargins }
return ConstraintItem(target: other, attributes: attributes)
}
@discardableResult
public func equalToSuperviewMargin(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(relatedConstraintItem, relation: .equal, file: file, line: line)
}
@discardableResult
public func lessThanOrEqualToSuperviewMargin(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(relatedConstraintItem, relation: .lessThanOrEqual, file: file, line: line)
}
@discardableResult
public func greaterThanOrEqualToSuperviewMargin(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(relatedConstraintItem, relation: .greaterThanOrEqual, file: file, line: line)
}
}
With this i can do this, which looks good, is easy to read, and works great:
view.snp.makeConstraints { (make) in
make.edges.equalToSuperviewMargin()
}
The correct way to do this is to pin it to the margins, the reason why is because if the margins change the auto-layout engine will re-calculate the layout.
If you manually offset based on the layout margins and the margins change you must also manually run updateConstraints which is a pitfall.
right, having something such as following would be enough too:
extension ConstraintMakerRelatable {
@discardableResult
public func equalToSuperviewMarginGuide(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.")
}
return self.equalTo(other.layoutMarginsGuide)
}
}
unfortunately we can't extend those classes as they are internally protected
Most helpful comment
right, having something such as following would be enough too:
unfortunately we can't extend those classes as they are internally protected