Skip to content

A Swift way to code Auto Layout constraints — powerful, expressive, and safe.

License

Notifications You must be signed in to change notification settings

stevebrambilla/LayoutExpressions

Repository files navigation

Layout Expressions

SwiftPM compatible Carthage compatible Travis CI

LayoutExpressions is a lightweight and easy-to-use library for defining Auto Layout constraints, designed for Swift. It lets you describe constraints expressively and with type safety:

NSLayoutConstraint.activateLayout {
    subviewB.anchors.allEdges == subviewA.anchors.allEdges - 10
}

instead of:

let top = subview.topAnchor.constraint(equalTo: container.topAnchor, constant: 10)
let bottom = subview.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -10)
let leading = subview.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 10)
let trailing = subview.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -10)
NSLayoutConstraint.activate([top, bottom, leading, trailing])

This example uses a Composite Expression to create four constraints from a single expression. More details below.

Usage

Add NSLayoutConstraints to your views by typing your constraints as view1.attribute1 == view2.attribute2 × multiplier + constant. You can use any of ==, >=, or <= as relations, and you can omit the multiplier and constant if they aren't needed:

// A basic layout expression for the y-axis:
subview.anchors.top == container.anchors.top

// With multiplier and constant:
subview2.anchors.width >= subview1.anchors.width * 2 + 10

LayoutExpressions supports Swift 5.1 function builders, allowing you to easily create dynamic layouts:

NSLayoutConstraint.activateLayout {
    if pinTopAndBottomToSafeArea {
        subview.anchors.verticalEdges == container.anchors.safeArea.verticalEdges
    } else {
        subview.anchors.verticalEdges == container.anchors.verticalEdges
    }
    subview.anchors.horizontalEdges == container.anchors.horizontalEdges
}

To access the constraints without activating them you can use evaluateLayout() instead of activateLayout():

let constraints = NSLayoutConstraint.evaluateLayout {
    subview.anchors.center == container.anchors.center
}
// `constraints` contains a .centerX constraint and a .centerY constraint

Set priorities for your constraints by using the <~ operator after your expression:

subview1.anchors.width >= subview2.anchors.width <~ .defaultHigh

LayoutExpressions provides the following extensions for layout anchors:

View Anchors Layout Guide Anchors
view.anchors.top guide.anchors.top
view.anchors.bottom guide.anchors.bottom
view.anchors.leading guide.anchors.leading
view.anchors.trailing guide.anchors.trailing
view.anchors.left guide.anchors.left
view.anchors.right guide.anchors.right
view.anchors.centerX guide.anchors.centerX
view.anchors.centerY guide.anchors.centerY
view.anchors.width guide.anchors.width
view.anchors.height guide.anchors.height
view.anchors.firstBaseline
view.anchors.lastBaseline

As well as convenience shorthands for accessing the anchors of common layout guides:

UIView
Safe Area view.anchors.safeArea.*
Layout Margins view.anchors.margins.*
Readable Content Guide view.anchors.readable.*

These shorthands can further simplify layout expressions that use layout guides, for example: subview.anchors.top == container.anchors.safeArea.top

Composite Expressions

LayoutExpressions makes common layout patterns even easier with composite expressions. Composite expressions are expressions that evaluate to more than one NSLayoutConstraint.

For example, subview.anchors.allEdges == container.anchors.allEdges will pin all edges of subview to container. This expression evaluates to four distinct NSLayoutConstraints -- one for each edge. Use them to make your code even more concise and clear.

LayoutExpressions provides the following extensions for composite layout anchors:

View Anchors LayoutGuide Anchors
view.anchors.allEdges guide.anchors.allEdges
view.anchors.verticalEdges guide.anchors.verticalEdges
view.anchors.horizontalEdges guide.anchors.horizontalEdges
view.anchors.center guide.anchors.center
view.anchors.size guide.anchors.size

Edges

view.anchors.allEdges evaluates to constraints for .top, .bottom, .leading, and .trailing. All relations are supported: ==, >=, <=.

// Pin the edges of subview to container.
subview.anchors.allEdges == container.anchors.allEdges

// Use the '-' operator to inset all edges of subview by 10 pts.
subview.anchors.allEdges == container.anchors.allEdges - 10

view.anchors.verticalEdges evaluates to constraints for .top and .bottom; and view.anchors.horizontalEdges evaluates to constraints for .leading and .trailing. All relations are supported: ==, >=, <=.

// Pin the vertical edges of subview to the container's safe area.
subview.anchors.verticalEdges == container.anchors.allEdges

// Pin the horizontal edges of subview to the container, inset by 10 pts.
subview.anchors.horizontalEdges == container.anchors.horizontalEdges - 10

Size

view.anchors.size evaluates to constraints for .width and .height. All relations are supported: ==, >=, <=.

// Pin the size of subview to the size of container.
subview.anchors.size == container.anchors.size

// Pin the size of subview to the size of container, with an offset.
subview.anchors.size == container.anchors.size + Size(width: -20, height: -10)

// Pin the size of subview to a fixed size.
subview.anchors.size == Size(width: 320, height: 200)

Center

anchors.center evaluates to constraints for .centerX and .centerY. Only the == relation is supported.

// Pin the center of subview to the center of container.
subview.anchors.center == container.anchors.center

// Pin the center of subview to the center of container, with an offset.
subview.anchors.center == container.anchors.center + Offset(horizontal: 0, vertical: -10)

Installation

LayoutExpressions supports macOS 10.13+, iOS 9.0+, and tvOS 9.0+.

Swift Package

In Xcode 11, use the repository URL in the Swift Packages screen:

https://github.com/stevebrambilla/LayoutExpressions

Carthage

If you’re using Carthage, simply add LayoutExpressions to your Cartfile:

github "stevebrambilla/LayoutExpressions" ~> 2.0

Contact

License

LayoutExpressions is available under the MIT license. See the LICENSE file for more info.

About

A Swift way to code Auto Layout constraints — powerful, expressive, and safe.

Resources

License

Stars

Watchers

Forks

Packages