Swiftpack.co - Package - dfed/Relativity

Relativity

CI Status Carthage Compatibility Version License Platform

Relativity provides a DSL for programmatic layout that makes it easy to achieve pixel-perfect spacing and alignment.

Programmatic Layout

There are four basic steps to laying out views programmatically.

  1. Create views. Do this in init or viewDidLoad.
  2. Create view hierarchy with addSubview(). Do this in init or viewDidLoad.
  3. Size views. Do this in layoutSubviews.
  4. Position views. Do this in layoutSubviews.

Positioning Views

Each view has nine anchors that are used for alignment.

topLefttoptopRight
leftmiddleright
bottomLeftbottombottomRight

Positioning views is done by aligning the desired anchor on a view to another view’s anchor, plus an offset. A --> moves the view on the left side to the position described on the right side. A <-- moves the view on the right side to the position described on the left side. You can also explicitly align views using the align(to:xOffset:yOffset) method in ViewPosition.swift.

Examples

To align view a to be 10 points to the left of view b:

  a.right --> 10.horizontalOffset + b.left

To align view a to be 10 points to the right of view b:

  b.right + 10.horizontalOffset <-- a.left

To align view a to be 10 points below its superview’s top center:

  a.top --> 10.verticalOffset + .top

For more examples, check out the ViewPositionVisualization playground page.

UILabels

Relativity makes it easy to position your UILabels to your designer’s spec. Design teams (and design products like Sketch and Zeplin) measure the vertical distance to a label using the font’s cap height and baseline. Relativity’s align methods measure UILabel distances the same way. So if your spec says that label b should be eight vertical points below label a, all you need is:

  a.bottom --> 8.verticalOffset + b.top

For a visual example, check out the FontMetricsVisualization playground page.

Flexible distribution of subviews

Since views need to be laid out flexibly over various iOS device sizes, Relativity has the ability to easily distribute subviews with flexible positioning along an axis.

Subview distribution can be controlled by positioning fixed and flexible spacers in between views. Fixed spaces represent points on screen. Fixed spaces are created by inserting CGFloatConvertible (Int, Float, CGFloat, or Double) types into the distribution expression, or by initializing a .fixed(CGFloatConvertible) enum case directly. Flexible spacers represent proportions of the remaining space in the superview after the subviews and fixed spacers have been accounted for. You can create flexible spacers by surrounding an Int with a spring ~ operator, or by initializing the .flexible(Int) enum case directly. A ~2~ represents twice the space that ~1~ does. Views, fixed spacers, and flexible spacers are bound together by a bidirectional anchor <> operator.

Examples

To equally distribute subviews a, b, and c at equal distances along a horizontal axis:

  superview.distributeSubviewsHorizontally() {
    a <> ~1~ <> b <> ~1~ <> c
  }

To make the space between a and b twice as large as the space between b and c:

  superview.distributeSubviewsHorizontally() {
    a <> ~2~ <> b <> ~1~ <> c
  }

To pin a to be 8pts from the left side, and distribute b and c with equal spacing over the remaining space:

  superview.distributeSubviewsHorizontally() {
    8 <> a <> ~1~ <> b <> ~1~ <> c
  }

To equally distribute subviews a, b, and c at equal distances along a vertical axis, but align the subviews within the left half of superview:

  superview.distributeSubviewsVertically(within: CGRect(x: 0.0, y: 0.0, width: superview.bounds.midX, height: superview.bounds.height)) {
    a <> ~1~ <> b <> ~1~ <> c
  }

For a visual example, check out the ViewPositionVisualization playground page.

Pixel Rounding

Relativity ensures that you never align a frame to a non-integral pixel, so no need to worry about blurry UI! I’ve also vended a public PixelRounder for those who want to use it for frame sizing.

Sizing Views

Relativity makes it easy to size views based on the space between previously laid-out content. Use the |--| operator to determine the size between view anchors.

Examples

To size view b to fit between views a and c:

  b.bounds.size = a.topRight |--| c.bottomLeft

To size view b to fit between views a and c with a 16 point horizontal inset:

  b.bounds.size = a.topRight |--| c.bottomLeft + -16.horizontalOffset

To size view b to be the same height as view a, and fit between a and the right side of a's superview:

  b.bounds.size = CGSize(width: (a.right |--| .right).width, height: a.bounds.height)

Requirements

  • Xcode 8.0 or later.
  • iOS 8 or later.
  • Swift 3.0 or later.

Installation

CocoaPods

To install Relativity in your iOS project with CocoaPods, add the following to your Podfile:

platform :ios, '8.0'
pod 'Relativity', '~> 0.9.0'

Carthage

To install Relativity in your iOS project with Carthage, add the following to your Cartfile:

github "dfed/Relativity"

Run carthage to build the framework and drag the built Relativity.framework into your Xcode project.

Swift Package Manager

To install Relativity in your iOS project with Swift Package Manager, the following definition can be added to the dependencies of your Project:

  .Package(url: "https://github.com/dfed/Relativity.git", majorVersion: 0, minor: 9),

Submodules

To use git submodules, checkout the submodule with git submodule add git@github.com:dfed/Relativity.git, drag Relativity.xcodeproj to your project, and add Relativity as a build dependency.

Contributing

I’m glad you’re interested in Relativity, and I’d love to see where you take it. Please read the contributing guidelines prior to submitting a Pull Request.

Thanks, and happy positioning!

Attribution

Shout out to Peter Westen who inspired the creation of this library.

Github

link
Stars: 14
Help us keep the lights on

Dependencies

Used By

Total:

Releases

0.9.5 - Oct 3, 2018

  • Fixed a rounding error in SubviewDistributor that could cause subviews distributed within a sub-rect to be misaligned by a single pixel.

0.9.4 - Apr 20, 2017

  • Properly calculate distribution of subviews within inset bounds

0.9.3 - Mar 30, 2017

  • Introduce |--| for measuring distance between ViewPositions
  • Add hook that allows adopting projects to change the behavior of assert within Relativity

0.9.2 - Mar 28, 2017

  • Measuring distance between points entirely ignore transforms

0.9.1 - Jan 31, 2017

  • Align views via the center point in order to not interfere with transforms