GithubHelp home page GithubHelp logo

simoneconnola / constrainable Goto Github PK

View Code? Open in Web Editor NEW
26.0 1.0 1.0 55 KB

simple declarative autolayout µframework based on Swift 4 KeyPath

Objective-C 3.68% Swift 96.32%
swift4 autolayout syntactic-sugar keypath

constrainable's Introduction

Constrainable

Swift Carthage compatible

Based on Chris Eidhof's idea and Marcin Siemaszko's expanded implementation, a programmatic autolayout µframework that supports Keypath–based declarative layout for both views and layout guides

At a glace:

A simple layout without Constrainable:

let view = UIView()
let container = UILayoutGuide()
let firstLabel = UILabel()
let secondLabel = UILabel()
let spacer = UILayoutGuide()

view.addSubview(firstLabel)
view.addSubview(secondLabel)
view.addLayoutGuide(container)
view.addLayoutGuide(spacer)

firstLabel.translatesAutoresizingMaskIntoConstraints = false
secondLabel.translatesAutoresizingMaskIntoConstraints = false

// Container has the same edges as the view's layoutMarginsGuide
NSLayoutConstraint.activate([
    container.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
    container.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor),
    container.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
    container.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
])

// firstLabel and secondLabel are vertically centered in the container, have the same width and are separated by a 20 points spacer
NSLayoutConstraint.activate([
    firstLabel.centerYAnchor.constraint(equalTo: container.centerYAnchor),
    firstLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor),
    firstLabel.trailingAnchor.constraint(equalTo: spacer.leadingAnchor),

    spacer.widthAnchor.constraint(equalToConstant: 20),

    secondLabel.centerYAnchor.constraint(equalTo: firstLabel.centerYAnchor),
    secondLabel.leadingAnchor.constraint(equalTo: spacer.trailingAnchor),
    secondLabel.trailingAnchor.constraint(equalTo: container.trailingAnchor),
    secondLabel.widthAnchor.constraint(equalTo: firstLabel.widthAnchor),
])

With Constrainable:

let view = UIView()
let container = UILayoutGuide()
let firstLabel = UILabel()
let secondLabel = UILabel()
let spacer = UILayoutGuide()

view.addSubview(firstLabel)
view.addSubview(secondLabel)
view.addLayoutGuide(container)
view.addLayoutGuide(spacer)

// Container has the same edges as the view's layoutMarginsGuide
container.activate(
    constraint(edgesTo: view.layoutMarginsGuide)
)

// firstLabel and secondLabel are vertically centered in the container, have the same width and are separated by a 20 points spacer
firstLabel.activate([
    constraint(same: \.centerYAnchor, as: container),
    constraint(same: \.leadingAnchor, as: container),
    constraint(\.trailingAnchor, to: \.leadingAnchor, of: spacer)
])

spacer.activate([
    constraint(\.widthAnchor, to: 20)
])

secondLabel.activate([
    constraint(same: \.centerYAnchor, as: firstLabel),
    constraint(same: \.trailingAnchor, as: container),
    constraint(\.leadingAnchor, to: \.trailingAnchor, of: spacer),
    constraint(same: \.widthAnchor, as: firstLabel),
])

Full NSLayoutConstraint features:

You can specify the kind of relation between constrainable objects (equal, lessThanOrEqual, greaterThanOrEqual), the constant, the multiplier (even for NSLayoutAnchor), and the layout priority

constraint(\.topAnchor, to: \.bottomAnchor, of: someView, relation: .lessThanOrEqual, offset: 10, multiplier: 0.5, priority: .defaultLow)

Shorthand:

Since version 1.0 you can decide to use shorthand for KeyPaths:

constraint(.top, to: .bottom, of: someView)

instead of:

constraint(\.topAnchor, to: \.bottomAnchor, of: someView)

with autocomplete! 🎉

Tips and tricks:

• You can constrain a dimension to a constant:

constraint(.width, to: 10)
constraint(.height, to: 10)

• If you are constraining two objects to the same anchor, you can use the "same" shorthand:

// This:
constraint(.top, to: .top, of: someView)
constraint(.width, to: .width, of: someView)

// Is the same as this:
constraint(same: .top, as: someView)
constraint(same: .width, as: someView)

• You can constrain both dimension at the same time:

// This:
constraint(same: .height, as: someView, multiplier: 2)
constraint(same: .width, as: someView, multiplier: 2)

// Is the same as this:
constraint(sizeAs: someView, multiplier: 2)

• You can constrain all the edges at once (with insets, even):

// This:
constraint(same: .top, as: someView, offset: 10)
constraint(same: .bottom, as: someView, offset: -10)
constraint(same: .leading, as: someView, offset: 10)
constraint(same: .trailing, as: someView, offset: -10)

// Is the same as this:
let padding = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
constraint(edgesTo: someView, with: padding)

Note: The last two functions return an array of constraints instead of a single one!

// WRONG:
someOtherView.activate([
    constraint(edgesTo: someView)
])

// RIGHT:
someOtherView.activate(
    constraint(edgesTo: someView)
)
// WRONG:
someOtherView.activate([
    constraint(sizeAs: someView),
    constraint(same: .centerX, as: someView),
    constraint(same: .centerY, as: someView)
])

// RIGHT:
someOtherView.activate(
    constraint(sizeAs: someView) + [
    constraint(same: .centerX, as: someView),
    constraint(same: .centerY, as: someView)
])

• For animations, you can store the constraint in a lazy variable:

lazy var animatableCenterY = constraint(same: .centerY, as: someView)(someOtherView)

someOtherView.activate([
... // Other constraints
])
animatableCenterY.isActive = true

animatableCenterY.constant = 100
UIView.animate(withDuration: 0.25) {
    self.view.layoutIfNeeded()
}

constrainable's People

Contributors

simoneconnola avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

ryantstone

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.