Paralayout gives UIKit pixel-perfect layout without a constraint solver
Paralayout is a set of simple, useful, and straightforward utilities that enable pixel-perfect layout in iOS. Your designers will love you.
At a glance
- What is it?
- Paralayout is a set of Swift utilities for pixel-perfect layout on iOS: sizing with constraints, alignment that snaps to the nearest pixel, subview distribution, aspect ratio arithmetic, interpolation for multi-phase animations and font cap insets. It is Apache-2.0 licensed, needs iOS 13 with Swift 5.9, and its newest tagged release is 1.0.0 from 2024.
- Who is it for?
- iOS teams that lay out views by frame and want the arithmetic to be right should adopt Paralayout, because the alignment, sizing and distribution helpers snap to the pixel and remove the rounding bugs that make a layout look slightly wrong. It is the wrong tool if your app is built on Auto Layout constraints, since Paralayout deliberately sets frames instead of describing them, and it is the wrong tool for SwiftUI, which the README does not mention at all.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A menu of layout utilities rather than a layout system
Paralayout is a set of simple, useful and straightforward utilities that enable pixel-perfect layout in iOS. The repository description adds the line your designers will love you, which is a fair summary of what the library is for.
The framing that matters is in the usage section. Paralayout is a set of à la carte utilities, of which you can use as much or as little functionality as you like. There is no required base class, no container view you must adopt, and no layout engine that owns your view hierarchy. You call the helpers you want on the views you already have.
That is a meaningfully different approach from the one UIKit ships with. Auto Layout is a constraint solver: you describe relationships, and the engine computes frames, with the rounding and ambiguity handling that come with solving a system of equations at run time. Paralayout operates one level down, on sizes and frames and offsets, and it takes responsibility for the arithmetic that usually goes wrong, which is the rounding to whole pixels and the alignment maths.
The repository is Square's, the code is Swift, and the topics list flexbox, ios, layout, pixel-perfect, swift, typesetting and uikit, which tells you the intended domain is UIKit view layout rather than anything wider.
The audience is therefore iOS engineers who are already setting frames, and who would like the numbers to be correct. Engineers who have committed to constraint-based layout will find the whole surface redundant, and the library has no stated story for SwiftUI.
Sizing views by extending sizeThatFits and sizeToFit
The first group of utilities is about sizing views, and the mechanism is an extension of the UIKit methods you already know.
Paralayout extends UIView.sizeThatFits(_:) and UIView.sizeToFit() to include constraints, which the README says gives more control over how subviews are sized.
The example is a header bar that should always be the full width of its container, but use its ideal height clamped to the height of the container. The README notes this is achievable in a single method call by combining the .fixedWidth and .maxHeight constraints:
headerBar.sizeToFit(
bounds.size,
constraints: [.fixedWidth, .maxHeight]
)The call takes a size to fit within, which here is the container's own bounds, and a set of constraints that qualify how the ideal size is used. The .fixedWidth constraint says the width is taken from the fitting size rather than from the view's own content, and .maxHeight caps the result at the height available.
The design point is that sizing is still expressed in terms of a fitting size plus a set of qualifiers, which is a small vocabulary compared with laying out a view through a constraint solver. It is a different answer to the same question: instead of describing the relationship between views, you describe the rule that computes one view's size.
Alignment that snaps to the nearest pixel
Alignment is the second group, and the README's phrase for the guarantee is that alignments are automatically snapped to the nearest pixel, saving you from fuzzy edges on your views due to bad layout math.
The core call aligns one view to another with an offset:
firstSubview.align(
.topCenter,
with: secondSubview,
.bottomCenter,
verticalOffset: 16
)The alignment points are named, so a view can be aligned by its top centre to another view's bottom centre, with a 16 point vertical offset. That is a single expression for what is usually a set of constraints plus a constant.
There are conveniences for the most common case, aligning to the superview:
someSubview.align(withSuperview: .center)And there is support for more complex alignment concepts for specialised use cases, such as aligning a label by its first line of text. That is done through a proxy object:
label.firstLineAlignmentProxy.align(
.leftCenter,
with: icon,
.rightCenter,
horizontalOffset: 8
)The proxy stands in for a specific part of the view rather than the view as a whole, which is the kind of detail that normally requires manual frame arithmetic.
For a team that has fought blurry text edges in a table view cell, the pixel snapping is the part that justifies the library, and it is applied automatically rather than being something you opt into.
Distribution and aspect ratio as value types
On top of sizing and aligning, Paralayout adds two abstractions.
Distribution solves the common scenario of distributing views across a view on either the vertical or horizontal axis. The example distributes a series of views inside a container, with 16 points of space between each subview and any additional space distributed equally above and below:
containerView.applyVerticalSubviewDistribution(
[
1.flexible,
titleLabel,
16.fixed,
bodyLabel,
16.fixed,
actionButton,
1.flexible,
]
)The list mixes real views with numbers, and the numbers carry an attribute: 1.flexible is flexible space and 16.fixed is a fixed gap. Reading the list top to bottom gives the layout, and the flexible entries at both ends take up whatever is left over. That is a layout expressed as data, in the spirit of a stack view but without requiring a container to own the subviews.
The other abstraction is AspectRatio, and the README's claim is that working with aspect ratios has traditionally involved some easy-to-mess-up math. The type is created from any size, rect, or width and height value, and it computes pixel-snapped frame rectangles:
videoPlayer.frame = AspectRatio.widescreen.rect(toFit: bounds, at: .topCenter, in: view)The call fits a rectangle of the given ratio into the available bounds and places it at a named alignment point inside a view, again with the snapping applied for you.
Interpolation for multi-phase layout transitions
The remaining utilities deal with motion and with typography.
Interpolation is a value type that is simply a value between 0 and 1, and the README's description of it is that it makes computing that value, and deriving a new value from it, without the arithmetic, so you can get the math right for multi-phase layout transitions and animations.
// Determine how far we are into the transition of collapsing the header.
let headerCollapseAmount = Interpolation(of: header.bounds.height, from: maxHeaderHeight, to: minHeaderHeight)
// The icon shrinks to half its usual size...
let avatarSize = headerCollapseAmount.interpolate(from: 80, to: 40)
avatar.bounds.size = CGSize(width: avatarSize, height: avatarSize)
// ...as it completely fades out.
avatar.alpha = headerCollapseAmount.interpolate(from: 1, to: 0)The pattern is the point. One object carries the progress of the transition, and every property that depends on that progress is derived from it with the same call, so the size and the alpha cannot drift out of sync with each other. It is a small, well-defined type for a problem that is usually solved with a scattering of magic numbers.
For typography, the README points at a problem that is deterministic but non-obvious: the extra space within a label above the cap height and below the baseline of its font, especially at different scale factors. The LabelCapInsets value type encapsulates that logic, so a view that has to line up with the text rather than the label bounds can do so without recomputing font metrics by hand.
Four package managers, and a version story that needs reading
Paralayout is distributed through every major iOS dependency route, and the README gives the exact snippet for each.
CocoaPods:
pod 'Paralayout'Swift Package Manager:
dependencies: [
.package(name: "Paralayout", url: "https://github.com/square/Paralayout.git", from: "2.0.0"),
]Bazel:
bazel_dep(name = "paralayout", version = "2.0.0")Carthage:
github "Square/Paralayout"Those snippets contain a detail that is easy to skim past. The Swift Package Manager and Bazel instructions both point at 2.0.0, while the newest tagged release listed for the repository is 1.0.0 from 2024-04-08, and the CocoaPods and Carthage instructions name no version at all. So the two modern package managers are telling you to take 2.0.0, and the release list has not caught up. That is worth resolving before you pin a version, because the API surface described in the README may belong to the 2.0.0 line rather than to the 1.0.0 tag.
The build requirements are iOS 13.0 or later, Xcode 15.0 or later and Swift 5.9. The repository carries a Package.swift and a separate [email protected], which is the usual way to offer a manifest variant for an older toolchain, alongside a MODULE.bazel and a WORKSPACE.bzlmod for the Bazel route, a Paralayout.podspec, a Gemfile with a Gemfile.lock, and a .bazelversion.
The Example directory contains a demo application, ParalayoutDemo.xcodeproj, and a ParalayoutSnapshotTests directory, so the visual behaviour of the layout helpers is covered by snapshot tests rather than left to assertion.
Where Paralayout is the wrong tool
The limits follow from a design decision that is stated but not argued in the README.
The first is that Paralayout sets frames. Everything in the library is about computing a size, an offset or a rectangle and applying it, and the pixel snapping exists precisely because it is doing the rounding the constraint solver would otherwise do. If your codebase is built around Auto Layout, adopting Paralayout means replacing constraint code with frame code, which is a rewrite rather than an addition, and a layout that is wrong in a constraint system is often easier to fix there than in arithmetic.
The second is the platform and language scope. The topics name uikit, the requirements name iOS 13, and the README does not mention SwiftUI at all. An app built with SwiftUI has no use for any of it, and the type names in the examples, sizeThatFits, sizeToFit and the alignment proxies, are UIKit concepts.
The third is maintenance. The repository is not archived, and the last push was on 2026-04-20, which is more than six months ago, so it is not a project that is currently receiving changes. The newest tagged release is 1.0.0 from 2024-04-08, and the package manager instructions point at 2.0.0, which suggests the development line moved on without new tags being the thing you install.
The fourth is the scope of the library itself. It is a menu of utilities, and the README says as much, so there is no layout container, no constraint solver, and no automatic handling of safe areas, dynamic type, rotation or size class changes. Those remain your job.
The licence is Apache-2.0, with a LICENSE file at the repository root, so embedding the library in a commercial app carries the usual notice requirement and nothing more.
Editorial conclusion
iOS teams that lay out views by frame and want the arithmetic to be right should adopt Paralayout, because the alignment, sizing and distribution helpers snap to the pixel and remove the rounding bugs that make a layout look slightly wrong. It is the wrong tool if your app is built on Auto Layout constraints, since Paralayout deliberately sets frames instead of describing them, and it is the wrong tool for SwiftUI, which the README does not mention at all. Before adopting, check which iOS version and Swift toolchain you are on, since the requirements are iOS 13 or later, Xcode 15 or later and Swift 5.9, and note that the newest tagged release is 1.0.0 while the package manager instructions point at 2.0.0.
Frequently asked questions
How do I add Paralayout to an iOS project?
The README gives the snippet for each route. CocoaPods takes pod 'Paralayout', Swift Package Manager takes a .package entry with the Paralayout repository url and from: "2.0.0", Bazel takes bazel_dep(name = "paralayout", version = "2.0.0"), and Carthage takes github "Square/Paralayout".
What are the system requirements for Paralayout?
The README lists iOS 13.0 or later, Xcode 15.0 or later and Swift 5.9. The repository carries both a Package.swift and a [email protected], which covers Swift Package Manager setups on an older toolchain.
What does Paralayout do about blurry edges?
Alignments are automatically snapped to the nearest pixel, which the README presents as a way to avoid fuzzy edges caused by bad layout math. The AspectRatio type also computes pixel-snapped frame rectangles.
Does Paralayout work with Auto Layout or SwiftUI?
It is built on UIKit view layout, and the README describes it as à la carte utilities that extend UIView.sizeThatFits and sizeToFit and set frames. SwiftUI is not mentioned anywhere in the documentation.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/square-paralayout)Was this useful?