Elegant library that wraps working with frames with a nice chaining syntax.

Related tags

Layout swift ios layout
Overview

Framezilla

Build Status Version Carthage Compatible Platform Swift 4.0 License

Everyone wants to see smooth scrolling, that tableview or collectionview scrolls without any lags and it's right choice. But the constraints do not give it for us. Therefore, we have to choose manual calculation frames, but sometimes, when cell has a complex structure, code has not elegant, beautiful structure.

So, it's library for those, who want to see smooth scrolling with elegant code under the hood!

#Enjoy reading! 🎉

Framezilla is the child of Framer (analog of great layout framework which wraps manually calculation frames with a nice-chaining syntax), but only for Swift.

Installation 🔥

CocoaPods

CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over eighteen thousand libraries and can help you scale your projects elegantly. You can install it with the following command:

$ sudo gem install cocoapods

To integrate Framezilla, simply add the following line to your Podfile:

pod "Framezilla"

Then, run the following command:

$ pod install

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate Framezilla into your Xcode project using Carthage, specify it in your Cartfile:

github "Otbivnoe/Framezilla"

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

Features 💥

  • Edges with superview
  • Width / Height
  • Top / Left / Bottom / Right
  • CenterX / CenterY / Center (between views)
  • SizeToFit / SizeThatFits / WidthToFit / HeightToFit
  • Container
  • Stack
  • Optional semantic - and
  • Side relations: nui_left, nui_bottom, nui_width, nui_centerX and so on.
  • States
  • Safe area support 😱

Usage 🚀

Size (width, height)

There're a few methods for working with view's size.

You can configure width and height separately:

view.configureFrame { maker in
    maker.width(200).and.height(200)
}

or together with the same result:

view.configureFrame { maker in
    maker.size(width: 200, height: 200)
}

Also in some cases you want to equate the sides of two views with some multiplier.

For example:

view.configureFrame { maker in
    maker.width(to: view1.nui_height, multiplier: 0.5)
    maker.height(to: view1.nui_width) // x1 multiplier - default
}

Edges

Framezilla has two method for comfortable creating edge-relation.

Either you can create edge relation so

view.configureFrame { maker in
    maker.edges(insets: UIEdgeInsetsMake(5, 5, 5, 5)) // UIEdgeInsets.zero - default
}

or

view.configureFrame { maker in
    maker.edges(top: 5, left: 5, bottom: 5, right: 5)
}

the second method has optional parameters, so maker.edges(top: 5, left: 5, bottom: 5) also works correct, but does not create right relation, that in some cases is very useful.

Side relations (Top, left, bottom, right)

You can create edge relation, as shown above, but only use side relations.

view.configureFrame { maker in
    maker.top(inset: 5).and.bottom(inset: 5)
    maker.left(inset: 5).and.right(inset: 5)
}

Also possible to create relations with another view, not a superview:

// Red view
view.configureFrame { maker in
    maker.size(width: 30, height: 30)
    maker.left(to: self.view1.nui_right, inset: 5)
    maker.bottom(to: self.view1.nui_centerY)
}

In iOS 11 Apple has introduced the safe area, similar to topLayoutGuide and bottomLayoutGuide. Framezilla supports this new api as well:

content.configureFrame { maker in
    maker.top(to: nui_safeArea)
    maker.bottom(to: nui_safeArea)
    maker.right(to: nui_safeArea, inset: 10)
    maker.left(to: nui_safeArea, inset: 10)
}

Note: In earlier versions of OS than iOS 11, these methods create a relation to a superview, not the safe area.

Center relations

If you just want to center subview relative superview with constant width and height, this approach specially for you:

view.configureFrame { maker in
    maker.centerY().and.centerX()
    maker.size(width: 100, height: 100)
}

Also possible to set manually centerX and centerY. Just call setCenterX and setCenterY.

What if you want to join the center point of the view with the top right point of another view?

PFF, OKAY.

view.configureFrame { maker in
    maker.centerX(to: self.view1.nui_right, offset: 0)
    maker.centerY(to: self.view1.nui_top) //Zero offset - default
    maker.size(width: 50, height: 50)
}

SizeToFit and SizeThatFits

Very often you should configure labels, so there are some methods for comfortable work with them.

SizeToFit

label.configureFrame { maker in
    maker.sizeToFit() // Configure width and height by text length no limits
    maker.centerX().and.centerY()
}

SizeThatFits

But what if you have to specify edges for label?

label.configureFrame { maker in
    maker.sizeThatFits(size: CGSize(width: 200, height: 100))
    maker.centerX().and.centerY()
}

Container

Use this method when you want to calculate a width and height by wrapping all subviews.

You can also specify a special container relation:

public enum ContainerRelation {
    case width(Number)
    case height(Number)
    case horizontal(left: Number, right: Number)
    case vertical(top: Number, bottom: Number)
}

For instance, if you set a width for a container, only a dynamic height will be calculated.

NOTE:

It atomatically adds all subviews to the container. Don't add subviews manually.

If you don't use a static width for instance, important to understand, that it's not correct to call left and right relations together by subviews, because container sets width relatively width of subviews and here is some ambiguous.

let container = [content1, content2, content3, content4].container(in: view, relation: /* if needed */) {
    content1.configureFrame { maker in
        maker.centerX()
        maker.top()
        maker.size(width: 50, height: 50)
    }

    content2.configureFrame { maker in
        maker.top(to: content1.nui_bottom, inset: 5)
        maker.left()
        maker.size(width: 80, height: 80)
    }

    content3.configureFrame { maker in
        maker.top(to: content1.nui_bottom, inset: 15)
        maker.left(to: content2.nui_right, inset: 5)
        maker.size(width: 80, height: 80)
    }

    content4.configureFrame { maker in
        maker.top(to: content3.nui_bottom, inset: 5)
        maker.right()
        maker.size(width: 20, height: 20)
    }
}

// width and height are already configured
container.configureFrame { maker in
    maker.center()
}

If you have already configured container, then this method will be more convenient for you:

[content1, label1, label2, label3].configure(container: container, relation: .horizontal(left: 20, right: 20)) {
// do configuration
}

Cool things:

Sometimes you want to configure a few views with the same size, for examlple. There is a convinience method:

[view1, view2].configureFrames { maker in
    maker.size(width: 200, height: 100)
}

Stack

Framezilla allows you configure views like stack behaviour. Important to point out correct views order.

[view3, view2, view1].stack(axis: .horizontal, spacing: 3)

States

It's very convenient use many states for animations, because you can just configure all states in one place and when needed change frame for view - just apply needed state! Awesome, is'n it?

demo

override func viewDidLayoutSubviews() {
  
  super.viewDidLayoutSubviews()
  
  // state `DEFAULT_STATE`
  view1.configureFrame { maker in
      maker.centerX().and.centerY()
      maker.width(50).and.height(50)
  }
  
  view1.configureFrame(state: 1) { maker in
      maker.centerX().and.centerY()
      maker.width(100).and.height(100)
  }
}

set new state and animate it:

/* Next time when viewDidLayoutSubviews will be called, `view1` will configure frame for state 1. */
view1.nx_state = 1 // Any hashable value
view.setNeedsLayout()
UIView.animate(withDuration: 1.0) {
    self.view.layoutIfNeeded()
}

Also possible to apply many states in a row:

view1.configureFrame(states: [3, "state"]) { maker in
    maker.size(width: 200, height: 100)
}

Author 💪

Nikita Ermolenko, [email protected]

Thanks 👍

Thanks Artem Novichkov for the name of the library!

Thanks Evgeny Mikhaylov for 'state' feature!

Thanks Anton Kovalev for improving library!

Contribute 🙏

I would love you to contribute to Framezilla, check the CONTRIBUTING file for more info.

License

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

Comments
  • top/bottom странно работают...

    top/bottom странно работают...

    У ячеек справа хочу получить стрелочки. Выставляю ширину, прижимаю правый край к правому краю, высоты делаю одинаковые. Осталось по Y правильно расположить. Если располагаю используя centerY, то все хорошо. Если пытаюсь прижать верх или низ, то получаю как на втором скриншоте. Почему так?

    view.configureFrames { maker in
                maker.width(32.0)
                maker.right(to: nui_right, inset: 0.0)
                maker.centerY(to: nui_centerY, offset: 0.0)     // работает
                maker.height(to: nui_height, multiplier: 1.0)
    //            maker.bottom(to: nui_bottom, inset: 0.0)        // не работает
            }
    

    2017-02-01 1 15 52 2017-02-01 1 15 24

    question 
    opened by iwheelbuy 5
  • Как правильно работать с динамически изменяющимися отступами?

    Как правильно работать с динамически изменяющимися отступами?

    Есть у меня некоторая переменная inset от которой зависит положение subview на view и которая меняется, например, при сдвиге UIPanGestureRecognizer в таком ключе:

    func change(_ newInset: CGFloat) {
        view.inset = newInset
        view.setNeedsLayout()
    }
    

    Правильно ли я использую setNeedsLayout?

    P.S. Вот так выглядит код внутри layoutSubviews:

    subview.configureFrame { (maker) in
        maker.top().bottom().width(to: nui_width).right(inset: inset)
    }
    

    P.P.S. Все работает, просто хочу узнать правильно ли делаю

    question 
    opened by iwheelbuy 2
  • Default value for `edges` method

    Default value for `edges` method

    In documentation: func edges(insets: UIEdgeInsets = default) -> Maker

    The insets for setting relations for superview. UIEdgeInsets.zero - default insets.

    But when I try to ommit UIEdgeInsets value, for example:

    tableView.configureFrame { maker in
        maker.edges()
    }
    

    I see an error:

    Ambiguous use of 'edges'

    bug 
    opened by artemnovichkov 1
  • 👉👆🏻👇Side choosing ability

    👉👆🏻👇Side choosing ability

    Description

    Simple function for setting view with UIEdgeInsets and ability to choosing sides which will be pinned to superview. For example, it's useful when you have insets const but need to use only two of them for some view.

    Checklist

    • [x] Follows code style
    • [x] Has no SwiftLint warnings
    • [ ] Covered by tests
    • [x] All tests are passed
    • [x] Access control words were checked
    opened by stason314 0
  • Container's width / height are configured not properly

    Container's width / height are configured not properly

    For instance, we have the following code:

    [content1].configure(container: container, relation: .horizontal(left: 20, right: 20)) {
        content1.configureFrame { maker in
            maker.top()
            maker.size(width: 500, height: 60)
            maker.centerX()
        }
    }
    

    Container's width after the configuration should be is equal to 280, but this won't happen. It tries to wrap the all subviews and thus will ignore container's relations.

    bug 
    opened by Otbivnoe 0
  • Corner radius functions

    Corner radius functions

    Need to add two functions for setting a corner radius:

    1. Just setting a value:
    func cornerRadius(_ cornerRadius: Number) -> Maker
    
    1. Settings a value as either a half-width or half-height.
    func cornerRadius(byHalf type: Size) -> Maker
    
    enhancement 
    opened by Otbivnoe 0
  • Container enhancements

    Container enhancements

    Added a special container relation:

    enum ContainerRelation {
        case width(Number)
        case height(Number)
        case horizontal(left: Number, right: Number)
        case vertical(top: Number, bottom: Number)
    }
    

    if you set a width relation for a container, only a height will be calculated dynamically.

    Also, there's a new method, that uses an already configured container:

    func configure(container: UIView, relation: ContainerRelation?, installerBlock: () -> Void) {}
    
    enhancement 
    opened by Otbivnoe 0
  • `heightToFit` and `widthToFit` enhancements

    `heightToFit` and `widthToFit` enhancements

    Problem:

    Have the following code:

    // label has a long text ... 
    label.configureFrame { maker in
        maker.edges(top: 30, left: 10, right: 10)
        maker.heightToFit()
    }
    

    This code has one problem: heightToFit doesn't take into account the left and right relations - the height of the label will be as for a one-line label.

    Conclusion:

    Need to consider specific relations such as left and right together, width and width(to:).

    P.S. The similar for widthToFit. P.S. widthThatFits and heightThatFits will have the similar logic only with a max setted value.

    enhancement 
    opened by Otbivnoe 0
  • Safe area support

    Safe area support

    Add safe area support with the following syntax:

    content.configureFrame { maker in
        maker.top(to: nui_safeArea)
        maker.bottom(to: nui_safeArea)
        maker.right(to: nui_safeArea, inset: 10)
        maker.left(to: nui_safeArea, inset: 10)
    }
    

    safe_area

    enhancement 
    opened by Otbivnoe 0
  • Frame equals to another view frame

    Frame equals to another view frame

    I'm configuring frame like that:

    mapView.configureFrames { maker in
        maker.top(to: tableView.nui_top)
        maker.bottom(to: tableView.nui_bottom)
        maker.left(to: tableView.nui_left)
        maker.right(to: tableView.nui_right)
    }
    

    mapView and tableView are on the one subview level. Please, add sugar method to make one frame equals to another frame, for example:

    mapView.configureFrames { maker in
        maker.equal(to: tableView)
    }
    
    enhancement 
    opened by artemnovichkov 0
Releases(2.9.1)
  • 2.9.1(Feb 28, 2018)

  • 2.9.0(Feb 9, 2018)

  • 2.8.0(Feb 2, 2018)

  • 2.7.0-rc.1(Dec 29, 2017)

    Improvements:

    Changed the layout system - in previous versions of the library Maker changes the frame property of objects, now it changes the center and bounds.

    Source code(tar.gz)
    Source code(zip)
  • 2.7.0(Dec 28, 2017)

    Improvements:

    • heightToFit and widthToFit enhancements. Close #11

    Changes:

    • widthThatFits(width: Number) was renamed to widthThatFits(maxWidth: Number)
    • heightThatFits(height: Number) was renamed to heightThatFits(maxHeight: Number)
    Source code(tar.gz)
    Source code(zip)
  • 2.6.0(Dec 26, 2017)

    Features:

    • Added a new more flexible container method:
    let container = [content1, content2, content3, content4].container(in: view) {
      // configure frame of all subviews
    }
    
    Source code(tar.gz)
    Source code(zip)
  • 2.5.0(Dec 25, 2017)

  • 2.4.1(Dec 8, 2017)

  • 2.4.0(Nov 30, 2017)

    Features

    • Implemented centerX and centerY for relation views:

    maker.centerY(between: content1.nui_bottom, content2.nui_top)

    Fixes

    • Fixed view's binding to top / left / bottom / right sides of superview as a UIScrollView.
    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Oct 21, 2017)

  • 2.2.1(Aug 1, 2017)

    Fixes

    • Fixed bug with scrollview as a superview when contentSize == .zero.
    • Fixed bug with not correct superview configuration when view.superview.superview == nil.
    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Jun 30, 2017)

    Features:

    • Added margin(inset:) method.
    • Added centerX(between view1: view2:) and centerY(between view1: view2) methods.
    • Added >> and << operators for simplify configuration.
    Source code(tar.gz)
    Source code(zip)
  • 2.1.2(Jun 3, 2017)

  • 2.1.0(May 20, 2017)

    Features:

    • Added center(to:) method.

    Changes:

    • Renamed nui_state to nx_state due to runtime conflict with Objective-C library - Framer.

    Improvements:

    • Added workspace with example project.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Feb 20, 2017)

    Features:

    • Added RelationView - now it's not possible to forget to point out side relation: nui_top, nui_right etc in configuration method
    • State now supports AnyHashable value
    • Added support for multiple states in one configuration block
    • Added simple stack view
    • Added configuration method for array of views.
    • Added special Number protocol for comfortable working with additional configuration values. Earlier you must have been configured offset, inset values only by CGFloat.

    Fixes:

    • Fixed not correct behaviour of edges(insets:) method.

    Changes:

    • Removed например and по_сути optional methods
    • Renamed configureFrames(state: installerBlock) to configureFrame(state: installerBlock).

    Improvements:

    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Dec 21, 2016)

  • 1.2.0(Dec 10, 2016)

    Features:

    • Added equal(to:, insets:) method. It's similar to edges(insets:), but you can configure equality to another view, not a superview.
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Nov 12, 2016)

    Features:

    • Added heightToFit and widthToFit methods.

    Changes:

    • Renamed naprimer to например
    • Added по_сути property (RU only).
    Source code(tar.gz)
    Source code(zip)
Owner
Nikita Ermolenko
iOS evangelist | lover of music, bikes and photography | ex-Yandex
Nikita Ermolenko
CompositionalLayoutDSL, library to simplify the creation of UICollectionViewCompositionalLayout. It wraps the UIKit API and makes the code shorter and easier to read.

CompositionalLayoutDSL CompositionalLayoutDSL is a Swift library. It makes easier to create compositional layout for collection view. Requirements Doc

FABERNOVEL 44 Dec 27, 2022
Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [iOS/macOS/tvOS/CALayer]

Extremely Fast views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainabl

layoutBox 2.1k Dec 22, 2022
MisterFusion is Swift DSL for AutoLayout. It is the extremely clear, but concise syntax, in addition, can be used in both Swift and Objective-C. Support Safe Area and Size Class.

MisterFusion MisterFusion makes more easier to use AutoLayout in Swift & Objective-C code. Features Simple And Concise Syntax Use in Swift and Objecti

Taiki Suzuki 316 Nov 17, 2022
Harness the power of AutoLayout NSLayoutConstraints with a simplified, chainable and expressive syntax. Supports iOS and OSX Auto Layout

Masonry Masonry is still actively maintained, we are committed to fixing bugs and merging good quality PRs from the wider community. However if you're

null 18k Jan 5, 2023
GridExample - SwiftUI example working with grids

Working with SwiftUI grids LazyVGrid does not have a column span feature. This t

Alexander Kraev 2 Dec 27, 2022
An elegant pagination framework written in Swift.

Paginator Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installation Paginato

Grigor Hakobyan 2 Dec 16, 2021
BrickKit is a delightful layout library for iOS and tvOS. It is written entirely in Swift!

BrickKit is a delightful layout library for iOS and tvOS. It is written entirely in Swift! Deprecated BrickKit is being phased out at Wayfair, and the

Wayfair Tech – Archive 608 Sep 15, 2022
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.

?? UNMAINTAINED ?? This project is no longer used by LinkedIn and is currently unmaintained. LayoutKit is a fast view layout library for iOS, macOS, a

LinkedIn's Attic 3.2k Dec 27, 2022
An awesome Swift CSS DSL library using result builders.

An awesome Swift CSS DSL library using result builders.

Binary Birds 57 Nov 21, 2022
Intuitive and powerful Auto Layout library

Align introduces a better alternative to Auto Layout anchors. Semantic. Align APIs focus on your goals, not the math behind Auto Layout constraints. P

Alexander Grebenyuk 338 Oct 18, 2022
✂ Easy to use and flexible library for manually laying out views and layers for iOS and tvOS. Supports AsyncDisplayKit.

ManualLayout Table of Contents Installation Usage API Cheat Sheet Installation Carthage Add the following line to your Cartfile. github "isair/ManualL

Baris Sencan 280 Sep 29, 2022
An autolayout library for the damn fine citizens of San Diego.

Anchorman Do you think autolayout has to be hard? Nah. NSLayoutAnchor is pretty neat! But it's still a bit tedious of an API. Try writing .translatesA

Joe Fabisevich 79 May 25, 2022
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.

?? UNMAINTAINED ?? This project is no longer used by LinkedIn and is currently unmaintained. LayoutKit is a fast view layout library for iOS, macOS, a

LinkedIn's Attic 3.2k Jan 4, 2023
Compose is a library that helps you compose complex and dynamic views.

Compose is a data driven library that will help compose your complex and dynamic Views. It helps you create complex and dynamic Views using easy and s

OLX Brasil 123 Jun 9, 2021
SuperLayout is a Swift library that makes using Auto Layout a breeze.

SuperLayout is a library that adds a few custom operators to Swift that makes using the amazing NSLayoutAnchor API for Auto Layout a breeze. SuperLayo

Lionheart Software 53 Oct 12, 2022
This library allows you to make any UIView tap-able like a UIButton.

UIView-TapListnerCallback Example To run the example project, clone the repo, and run pod install from the Example directory first. Installation UIVie

wajeehulhassan 8 May 13, 2022
SwiftLayout - View hierarchy and autolayout DSL library

SwiftLayout view hierarchy and autolayout DSL library goal 뷰의 계층구조와 constraint 관

iOS Swifty Krew 104 Dec 28, 2022
Snitch - A handy library to access useful information about your application from the Home Screen

Snitch Access your app's useful information from Home Screen Table of Contents I

Tamerlan Satualdypov 12 Jan 2, 2023
Creating an iOS Library the Right Way

AppCircleSampleProject Installation Cocoapods AppCircleSampleProject is available through CocoaPods. To install it, simply add the following line to y

Ferhan Akkan 3 Aug 1, 2022