diff --git a/Docs/Benchmark-PinLayout-SourceCode.md b/Docs/Benchmark-PinLayout-SourceCode.md
new file mode 100644
index 00000000..fa0545a7
--- /dev/null
+++ b/Docs/Benchmark-PinLayout-SourceCode.md
@@ -0,0 +1,110 @@
+
PinLayout Benchmark Source code
+
+PinLayout's layout code is concise, clean and doesn't contain any computation compared to Manual Layouting source code.
+
+
+#### Manual layouting benchmark source code
+
+
+```
+override func layoutSubviews() {
+ super.layoutSubviews()
+
+ optionsLabel.frame = CGRect(x: bounds.width-optionsLabel.frame.width, y: 0,
+ width: optionsLabel.frame.width, height: optionsLabel.frame.height)
+ actionLabel.frame = CGRect(x: 0, y: 0, width: bounds.width-optionsLabel.frame.width, height: 0)
+ actionLabel.sizeToFit()
+
+ posterImageView.frame = CGRect(x: 0, y: actionLabel.frame.bottom,
+ width: posterImageView.frame.width, height: 0)
+ posterImageView.sizeToFit()
+
+ let contentInsets = UIEdgeInsets(top: 0, left: 1, bottom: 2, right: 3)
+ let posterLabelWidth = bounds.width-posterImageView.frame.width - contentInsets.left -
+ contentInsets.right
+ posterNameLabel.frame = CGRect(x: posterImageView.frame.right + contentInsets.left,
+ y: posterImageView.frame.origin.y + contentInsets.top,
+ width: posterLabelWidth, height: 0)
+ posterNameLabel.sizeToFit()
+
+ let spacing: CGFloat = 1
+ posterHeadlineLabel.frame = CGRect(x: posterImageView.frame.right + contentInsets.left,
+ y: posterNameLabel.frame.bottom + spacing,
+ width: posterLabelWidth, height: 0)
+ posterHeadlineLabel.sizeToFit()
+
+ posterTimeLabel.frame = CGRect(x: posterImageView.frame.right + contentInsets.left,
+ y: posterHeadlineLabel.frame.bottom + spacing, width: posterLabelWidth,
+ height: 0)
+ posterTimeLabel.sizeToFit()
+
+ posterCommentLabel.frame = CGRect(x: 0, y: max(posterImageView.frame.bottom,
+ posterTimeLabel.frame.bottom +
+ contentInsets.bottom),
+ width: frame.width, height: 0)
+ posterCommentLabel.sizeToFit()
+
+ contentImageView.frame = CGRect(x: frame.width/2 - contentImageView.frame.width/2,
+ y: posterCommentLabel.frame.bottom, width: frame.width, height: 0)
+ contentImageView.sizeToFit()
+
+ contentTitleLabel.frame = CGRect(x: 0, y: contentImageView.frame.bottom, width: frame.width, height: 0)
+ contentTitleLabel.sizeToFit()
+
+ contentDomainLabel.frame = CGRect(x: 0, y: contentTitleLabel.frame.bottom, width: frame.width, height: 0)
+ contentDomainLabel.sizeToFit()
+
+ likeLabel.frame = CGRect(x: 0, y: contentDomainLabel.frame.bottom, width: 0, height: 0)
+ likeLabel.sizeToFit()
+
+ commentLabel.sizeToFit()
+ commentLabel.frame = CGRect(x: frame.width/2-commentLabel.frame.width/2,
+ y: contentDomainLabel.frame.bottom,
+ width: commentLabel.frame.width, height: commentLabel.frame.height)
+
+ shareLabel.sizeToFit()
+ shareLabel.frame = CGRect(x: frame.width-shareLabel.frame.width, y: contentDomainLabel.frame.bottom,
+ width: shareLabel.frame.width, height: shareLabel.frame.height)
+
+ actorImageView.frame = CGRect(x: 0, y: likeLabel.frame.bottom, width: 0, height: 0)
+ actorImageView.sizeToFit()
+
+ actorCommentLabel.frame = CGRect(x: actorImageView.frame.right, y: likeLabel.frame.bottom,
+ width: frame.width-actorImageView.frame.width, height: 0)
+ actorCommentLabel.sizeToFit()
+}
+```
+
+### PinLayout benchmark source code
+
+```
+override func layoutSubviews() {
+ super.layoutSubviews()
+
+ let hMargin: CGFloat = 8
+ let vMargin: CGFloat = 2
+
+ optionsLabel.pin.topRight().margin(hMargin)
+ actionLabel.pin.topLeft().margin(hMargin)
+
+ posterImageView.pin.below(of: actionLabel, aligned: .left).marginTop(10)
+ posterNameLabel.pin.right(of: posterImageView, aligned: .top).margin(-6, 6).right(hMargin).sizeToFit()
+ posterHeadlineLabel.pin.below(of: posterNameLabel, aligned: .left).right(hMargin).marginTop(1).sizeToFit()
+ posterTimeLabel.pin.below(of: posterHeadlineLabel, aligned: .left).right(hMargin).marginTop(1).sizeToFit()
+
+ posterCommentLabel.pin.below(of: posterTimeLabel).left(hMargin).right().right(hMargin)
+ .marginTop(vMargin).sizeToFit()
+
+ contentImageView.pin.below(of: posterCommentLabel).hCenter().width(100%).sizeToFit()
+ contentTitleLabel.pin.below(of: contentImageView).left().right().marginHorizontal(hMargin).sizeToFit()
+ contentDomainLabel.pin.below(of: contentTitleLabel, aligned: .left).right().marginRight(hMargin)
+ .sizeToFit()
+
+ likeLabel.pin.below(of: contentDomainLabel, aligned: .left).marginTop(vMargin)
+ commentLabel.pin.top(to: likeLabel.edge.top).hCenter(50%)
+ shareLabel.pin.top(to: likeLabel.edge.top).right().marginRight(hMargin)
+
+ actorImageView.pin.below(of: likeLabel, aligned: .left).marginTop(vMargin)
+ actorCommentLabel.pin.right(of: actorImageView, aligned: .center).marginLeft(4)
+}
+```
diff --git a/Docs/Benchmark.md b/Docs/Benchmark.md
new file mode 100644
index 00000000..46a76ded
--- /dev/null
+++ b/Docs/Benchmark.md
@@ -0,0 +1,51 @@
+
+
+
+
+PinLayout Benchmark
+
+## Methodology
+
+##### LayoutKit Benchmark
+PinLayout's performance has been tested using a fork of [LayoutKit](https://github.com/mirego/LayoutKit). LayoutKit include an example app with a really nice and simple benchmark. It is used to compare LayoutKit with Auto layout, UIStackViews and manual layouting.
+
+The benchmark has been modified to also include [PinLayout](https://github.com/mirego/LayoutKit/blob/master/LayoutKitSampleApp/Benchmarks/FeedItemPinLayoutView.swift). Remark in the implemantation that PinLayout's layout code is concise, clean and doesn't contain any computation [compared to Manual Layouting source code](Benchmark-PinLayout-SourceCode.md).
+
+The benchmark include tests for the following layout systems:
+
+* Auto layout
+* Auto layout using UIStackViews
+* LayoutKit
+* Manual layout (i.e. set UIView's frame directly)
+* PinLayout
+
+Anyone who would like to integrate any other layout frameworks to this GitHub repository is welcome.
+
+##### Benchmark details
+The LayoutKit benchmark layout UICollectionView and UITableView cells in multiple pass, each pass contains more cells than the previous one. The **X axis** in following charts indicates the number of cell contained for each pass. The **Y axis** indicates the number of miliseconds to render all cells from one pass.
+
+Here are the rendering results to compare visual results:
+
+* [Auto layout rendering result](Benchmark/Benchmark-Autolayout.png)
+* [PinLayout rendering result](Benchmark/Benchmark-PinLayout.png)
+* [LayoutKit rendering result](Benchmark/Benchmark-LayoutKit.png)
+
+## Results
+
+As you can see in the following chart, PinLayout's performance is as fast as manual layouting, and up to **12x faster than auto layout**, and **16x faster than UIStackViews**. [LayoutKit](https://github.com/linkedin/LayoutKit) is also really fast, slightly slower than PinLayout and manual layouting.
+
+These results also means that PinLayout is by far faster than any layout frameworks that is built over auto layout ([SnapKit](https://github.com/SnapKit/SnapKit), [Stevia](https://github.com/freshOS/Stevia), [PureLayout](https://github.com/PureLayout/PureLayout), ...).
+
+It takes almost half a second (0.468 ms) to render 100 UICollectionView's cells using UIStackViews, and 1/3 of second (0.344) using auto layout on a iPhone 6S device.
+
+
+
+iPhone 6S - iOS 10.3.2
+
+
+
X axis in the number cells in a UICollectionView, and Y axis is the time in miliseconds to layout all cells.
+
+
+You can have a look at the [spreadsheet containing all the data](Benchmark/Benchmark-iPhone6S.xlsx)
+
+### Other device's chart will be coming soon...
diff --git a/Docs/Benchmark/Benchmark-Autolayout.png b/Docs/Benchmark/Benchmark-Autolayout.png
new file mode 100644
index 00000000..016b9ce1
Binary files /dev/null and b/Docs/Benchmark/Benchmark-Autolayout.png differ
diff --git a/Docs/Benchmark/Benchmark-LayoutKit.png b/Docs/Benchmark/Benchmark-LayoutKit.png
new file mode 100644
index 00000000..8ed6bac5
Binary files /dev/null and b/Docs/Benchmark/Benchmark-LayoutKit.png differ
diff --git a/Docs/Benchmark/Benchmark-PinLayout.png b/Docs/Benchmark/Benchmark-PinLayout.png
new file mode 100644
index 00000000..179ea540
Binary files /dev/null and b/Docs/Benchmark/Benchmark-PinLayout.png differ
diff --git a/Docs/Benchmark/Benchmark-iPhone6S.xlsx b/Docs/Benchmark/Benchmark-iPhone6S.xlsx
new file mode 100644
index 00000000..be936055
Binary files /dev/null and b/Docs/Benchmark/Benchmark-iPhone6S.xlsx differ
diff --git a/Docs/Benchmark/Chart-iPhone6S.png b/Docs/Benchmark/Chart-iPhone6S.png
new file mode 100644
index 00000000..d9e49cae
Binary files /dev/null and b/Docs/Benchmark/Chart-iPhone6S.png differ
diff --git a/Docs/Benchmark/LayoutKit-Benchmark-with-PinLayout-iPhone6S.xlsx b/Docs/Benchmark/LayoutKit-Benchmark-with-PinLayout-iPhone6S.xlsx
new file mode 100644
index 00000000..af562bd4
Binary files /dev/null and b/Docs/Benchmark/LayoutKit-Benchmark-with-PinLayout-iPhone6S.xlsx differ
diff --git a/README.md b/README.md
index 0f0aea1b..3ac4a235 100644
--- a/README.md
+++ b/README.md
@@ -16,14 +16,14 @@
-Swift manual views layouting without auto layout, no magic, pure code, full control. Concise syntax, readable & chainable.
+Swift manual views layouting without auto layout, no magic, pure code, full control and FAST! Concise syntax, readable & chainable.
> "No auto-layout constraints attached"
* [PinLayout principles and philosophy](#introduction)
-* [Installation](#installation)
+* [Performance](#performance)
* [Documentation](#documentation)
* [Layout using distances from superview’s edges](#distance_from_superview_edge)
* [Anchors](#anchors)
@@ -34,6 +34,7 @@ Swift manual views layouting without auto layout, no magic, pure code, full cont
* [Warnings](#warnings)
* [More examples](#more_examples)
+* [Installation](#installation)
* [FAQ](#faq)
* [Comments, ideas, suggestions, issues, ....](#comments)
@@ -42,6 +43,7 @@ Swift manual views layouting without auto layout, no magic, pure code, full cont
## PinLayout principles and philosophy
* Manual layouting. No magic, pure code, full control.
+* Fast, PinLayout exist to be simple and fast as possible! In fact it is fast as manual layouting. See [performance results below.](#performance)
* Layout one view at a time.
* Concise syntax. Layout most views using a single line.
@@ -71,39 +73,23 @@ A view can be layouted using PinLayout and later with another method/framework.
-## Installation
-
-### CocoaPods
-
-To integrate PinLayout into your Xcode project using CocoaPods, specify it in your `Podfile`:
-
-```ruby
- pod 'PinLayout'
-```
+# PinLayout's Performance
-Then, run `pod install`.
+PinLayout's performance has been measured using the excellent LayoutKit benchmark. PinLayout has been added to this benchmark to compare its performance.
-### Carthage
+As you can see in the following chart, PinLayout's performance is as fast as manual layouting, and up to **12x faster than auto layout**, and **16x faster than UIStackViews**.
-To integrate PinLayout into your Xcode project using Carthage, specify it in your `Cartfile`:
+These results also means that **PinLayout is by far faster than any layout frameworks that is built over auto layout**.
-```ogdl
-github "mirego/PinLayout"
-```
+[More details and explanation of the benchmark](Docs/Benchmark.md)
-Then, run `carthage update` to build the framework and drag the built `PinLayout.framework` into your Xcode project.
-
-### Swift Package Manager
-
-Once you have your Swift package set up, you only need to add PinLayout as a dependency of your `Package.swift`.
-
-```ogdl
-dependencies: [
- .Package(url: "https://github.com/mirego/PinLayout.git", majorVersion: 1)
-]
-```
+ Tested on a iPhone 6S iOS 10.3.2
+
+
+
X axis in the number cells in a UICollectionView, and Y axis is the time in miliseconds to layout all cells.
+
-
+
# Usage sample
###### Example:
@@ -133,13 +119,12 @@ override func layoutSubviews() {
}
```
-:pushpin: This example and some other examples are available in the **PinLayoutSample** project. Please note that you must do a `pod install` before running the sample project.
+:pushpin: This example and some other examples are available in the **Example** project. Please note that you must do a `pod install` before running the example project.
:pushpin: PinLayout doesn't use auto layout constraints, it is a framework that manually layout views. For that reason you need to update the layout inside either `UIView.layoutSubviews()` or `UIViewController.viewDidLayoutSubviews()` to handle container size's changes, including device rotation. You'll also need to handle UITraitCollection changes for app's that support multitask. In the example above PinLayout's commands are inside UIView's `layoutSubviews()` method.
-
# Documentation
## Layout using distances from superview’s edges
@@ -788,6 +773,40 @@ Cell D:
+## Installation
+
+### CocoaPods
+
+To integrate PinLayout into your Xcode project using CocoaPods, specify it in your `Podfile`:
+
+```ruby
+ pod 'PinLayout'
+```
+
+Then, run `pod install`.
+
+### Carthage
+
+To integrate PinLayout into your Xcode project using Carthage, specify it in your `Cartfile`:
+
+```ogdl
+github "mirego/PinLayout"
+```
+
+Then, run `carthage update` to build the framework and drag the built `PinLayout.framework` into your Xcode project.
+
+### Swift Package Manager
+
+Once you have your Swift package set up, you only need to add PinLayout as a dependency of your `Package.swift`.
+
+```ogdl
+dependencies: [
+ .Package(url: "https://github.com/mirego/PinLayout.git", majorVersion: 1)
+]
+```
+
+
+
## Coming soon
* minWidth/maxWidth, minHeight/maxHeight
* CALayer support
@@ -808,17 +827,19 @@ Cell D:
```
-## Comments, ideas, suggestions, issues, ....
+### Comments, ideas, suggestions, issues, ....
For any **comments**, **ideas**, **suggestions**, **issues**, simply open an [issue](https://github.com/mirego/PinLayout/issues).
-
-## Contributing
-1. Fork it!
-2. Create your feature branch: `git checkout -b my-new-feature`
-3. Commit your changes: `git commit -am 'Add some feature'`
-4. Push to the branch: `git push origin my-new-feature`
-5. Submit a pull request :D
+### Thanks
+PinLayout was inspired by other great layout frameworks, including:
+
+* [MCUIViewLayout](https://github.com/mirego/MCUIViewLayout)
+* HTML's CSS
+* [SnapKit](https://github.com/SnapKit/SnapKit)
+* [Stevia](https://github.com/freshOS/Stevia)
+* ... and even Auto layout :-)
+
## License
BSD 3-Clause License