Snapkit: Feature request: constraint equal/lessThanOrEqual/greaterThanOrEqual/ToSuperviewMargin

Created on 24 May 2017  路  2Comments  路  Source: SnapKit/SnapKit

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()
}
enhancement need info

Most helpful comment

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

All 2 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Shehryar picture Shehryar  路  7Comments

swiftli picture swiftli  路  9Comments

netgfx picture netgfx  路  3Comments

danieleggert picture danieleggert  路  3Comments

cooler333 picture cooler333  路  5Comments