Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/marty-suzuki/MisterFusion

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.
https://github.com/marty-suzuki/MisterFusion

autolayout carthage cocoapods ios iphone-x macos safe-area swift tvos

Last synced: about 2 months ago
JSON representation

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.

Lists

README

        

# MisterFusion

[![Platform](http://img.shields.io/badge/platform-iOS%20|%20tvOS%20|%20macOS-blue.svg?style=flat
)](https://developer.apple.com/iphone/index.action)
[![Language](http://img.shields.io/badge/swift-5-orange.svg?style=flat
)](https://developer.apple.com/swift)
[![Version](https://img.shields.io/cocoapods/v/MisterFusion.svg?style=flat)](http://cocoapods.org/pods/MisterFusion)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/MisterFusion.svg?style=flat)](http://cocoapods.org/pods/MisterFusion)
[![Build Status](https://travis-ci.org/marty-suzuki/MisterFusion.svg?branch=master)](https://travis-ci.org/marty-suzuki/MisterFusion)

![](./Images/logo.png)

MisterFusion makes more easier to use AutoLayout in Swift & Objective-C code.

## Features
- [x] Simple And Concise Syntax
- [x] Use in Swift and Objective-C
- [x] Support Size Class
- [x] Support Swift5
- [x] Support Swift4 (until 4.0.1)
- [x] Support SafeAreaπŸŽ‰ (Swift3.2 since 2.3.1, Swift4 since 3.1.0)
- [x] Support iOS
- [x] Support tvOS (since 3.2.0)
- [x] Support macOS (since 4.0.0)

#### MisterFusion Code for Swift

```swift
let view = UIView()
self.view.mf.addSubview(view, andConstraints:
view.top |+| 10,
view.right |-| 10,
view.left |+| 10,
view.bottom |-| 10
)
```

#### Ordinary Code for Swift

This is same implementation as above code, but this is hard to see.

```swift
let view = UIView()
self.view.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
self.view.addConstraints([
NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 10),
NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: -10),
NSLayoutConstraint(item: view, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 10),
NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: -10),
])
```

#### MisterFusion Code for Objective-C

```objective-c
UIView *view = [UIView new];
[self.view addLayoutSubview:view andConstraints:@[
view.Top .Constant(10.0f),
view.Right .Constant(-10.0f),
view.Left .Constant(10.0f),
view.Bottom.Constant(-10.0f)
]];
```

#### Ordinary Code for Objective-C

This is same implementation as above code, but this is hard to see.

```objective-c
UIView *view = [UIView new];
view.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview: view];
[self.view addConstraints:@[
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:10.0f],
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0f constant:-10.0f],
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:10.0f],
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.5f constant:-15.0f]
]];
```

#### Sample Layout

![](./Images/layout.png)

If you want to realize layout like a above image, needed code is only this.

```swift
let redView = UIView()
redView.backgroundColor = .red
self.view.mf.addSubview(redView, andConstraints:
redView.top |+| 10,
redView.right |-| 10,
redView.left |+| 10
)

let yellowView = UIView()
yellowView.backgroundColor = .yellow
self.view.mf.addSubview(yellowView, andConstraints:
yellowView.top |==| redView.bottom |+| 10,
yellowView.left |+| 10,
yellowView.bottom |-| 10,
yellowView.height |==| redView.height
)

let greenView = UIView()
greenView.backgroundColor = .green
self.view.mf.addSubview(greenView, andConstraints:
greenView.top |==| redView.bottom |+| 10,
greenView.left |==| yellowView.right |+| 10,
greenView.bottom |-| 10,
greenView.right |-| 10,
greenView.width |==| yellowView.width,
greenView.height |==| yellowView.height
)
```

## Installation

#### CocoaPods

MisterFusion is available through [CocoaPods](http://cocoapods.org). If you have cocoapods 0.39.0 or greater, you can install
it, simply add the following line to your Podfile:

pod 'MisterFusion'

In addtion, import **MisterFusion** like this.

##### Swift

import MisterFusion

##### Objective-C

#import

#### Carthage

If you’re using [Carthage](https://github.com/Carthage/Carthage), simply add
MisterFusion to your `Cartfile`:

```
github "szk-atmosphere/MisterFusion"
```
Make sure to add `MisterFusion.framework` to "Linked Frameworks and Libraries" and "copy-frameworks" Build Phases.

## Advanced Setting

You can set `multiplier`, `constant` and `priority` like this.
(This is same implementation as [first example](#misterfusion-code-for-swift).)

#### Swift

```swift
self.view.mf.addSubview(view, andConstraints:
view.top |==| self.view.top |*| 1 |+| 10 |<>| UILayoutPriorityRequired,
view.right |==| self.view.right |*| 1 |-| 10 |<>| UILayoutPriorityRequired,
view.left |==| self.view.left |*| 1 |+| 10 |<>| UILayoutPriorityRequired,
view.bottom |==| self.view.bottom |*| 1 |-| 10 |<>| UILayoutPriorityRequired
)
```

#### Objective-C

```objective-c
[self.view addLayoutSubview:view andConstraints:@[
view.Top .Equal(self.view.Top) .Multiplier(1.0f).Constant(10.0f) .Priority(UILayoutPriorityRequired),
view.Right .Equal(self.view.Right) .Multiplier(1.0f).Constant(-10.0f).Priority(UILayoutPriorityRequired),
view.Left .Equal(self.view.Left) .Multiplier(1.0f).Constant(10.0f) .Priority(UILayoutPriorityRequired),
view.Bottom.Equal(self.view.Bottom).Multiplier(1.0f).Constant(-10.0f).Priority(UILayoutPriorityRequired)
]];
```

## For Swift

#### Operators

- `|==|`, `|<=|`, `|>=|` ... `NSLayoutRelation` and fixed `height` and `width`
- `|*|`, `|/|` ... `multiplier`
- `|+|`, `|-|` ... `constant`
- `|<>|` ... `UILayoutPriority`
- `<|>` ... `UIUserInterfaceSizeClass` for VerticalSizeClass
- `<->` ... `UIUserInterfaceSizeClass` for HorizontalSizeClass
- `-=-` ... Identifier

#### UIView Extensions

```swift
public func addLayoutConstraint(_ misterFusion: MisterFusion) -> NSLayoutConstraint?
public func addLayoutConstraints(_ misterFusions: MisterFusion...) -> [NSLayoutConstraint]
public func addLayoutConstraints(_ misterFusions: [MisterFusion]) -> [NSLayoutConstraint]
public func addLayoutSubview(_ subview: UIView, andConstraint misterFusion: MisterFusion) -> NSLayoutConstraint?
public func addLayoutSubview(_ subview: UIView, andConstraints misterFusions: [MisterFusion]) -> [NSLayoutConstraint]
public func addLayoutSubview(_ subview: UIView, andConstraints misterFusions: MisterFusion...) -> [NSLayoutConstraint]
public func insertLayoutSubview(_ subview: UIView, at index: Int, andConstraint misterFusion: MisterFusion) -> NSLayoutConstraint?
public func insertLayoutSubview(_ subview: UIView, at index: Int, andConstraints misterFusions: [MisterFusion]) -> [NSLayoutConstraint]
public func insertLayoutSubview(_ subview: UIView, at index: Int, andConstraints misterFusions: MisterFusion...) -> [NSLayoutConstraint]
public func insertLayoutSubview(_ subview: UIView, belowSubview siblingSubview: UIView, andConstraint misterFusion: MisterFusion) -> NSLayoutConstraint?
public func insertLayoutSubview(_ subview: UIView, belowSubview siblingSubview: UIView, andConstraints misterFusions: [MisterFusion]) -> [NSLayoutConstraint]
public func insertLayoutSubview(_ subview: UIView, belowSubview siblingSubview: UIView, andConstraints misterFusions: MisterFusion...) -> [NSLayoutConstraint]
public func insertLayoutSubview(_ subview: UIView, aboveSubview siblingSubview: UIView, andConstraint misterFusion: MisterFusion) -> NSLayoutConstraint?
public func insertLayoutSubview(_ subview: UIView, aboveSubview siblingSubview: UIView, andConstraints misterFusions: [MisterFusion]) -> [NSLayoutConstraint]
public func insertLayoutSubview(_ subview: UIView, aboveSubview siblingSubview: UIView, andConstraints misterFusions: MisterFusion...) -> [NSLayoutConstraint]
```

#### Array Extensions

```swift
public func firstItem(_ view: UIView) -> [NSLayoutConstraint]
public func firstAttribute(_ attribute: NSLayoutAttribute) -> [NSLayoutConstraint]
public func relation(_ relation: NSLayoutRelation) -> [NSLayoutConstraint]
public func secondItem(_ view: UIView) -> [NSLayoutConstraint]
public func secondAttribute(_ attribute: NSLayoutAttribute) -> [NSLayoutConstraint]
```

You can get added `NSLayoutConstraint` with those functions.
This is a example.

```swift
let bottomConstraint: NSLayoutConstraint = self.view.addLayoutSubview(view, andConstraints:
view.top |+| 10,
view.right |-| 10,
view.left |+| 10,
view.bottom |-| 10
).firstAttribute(.bottom).first
```

You can use `Size Class` with `func traitCollectionDidChange(previousTraitCollection: UITraitCollection?)`.

![](./Images/misterfusion.gif)

This is an example Regular, Compact size for iPhone6s+.

```swift
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
guard let whiteView = whiteView, redView = redView else { return }
if let whiteViewHeightConstraint = whiteViewWidthConstraint {
redView.removeConstraint(whiteViewHeightConstraint)
}
self.whiteViewWidthConstraint = redView.mf.addConstraints(
whiteView.width |-| 20 <|> .compact <-> .regular,
whiteView.width |*| 0.5 |-| 10 <|> .regular <-> .compact
).firstAttribute(.width).first
}
```

* A detail sample is [here](./Example/MisterFusionSample/ViewController.swift)

#### Safe Area

You can use `view.safeArea.top` and so on. This is supported Safe Area.

```swift
view.mf.addConstraints(
yellowView.top |==| redView.bottom |+| 10,
yellowView.right |==| view.safeArea.right |-| 10,
yellowView.left |==| view.safeArea.left |+| 10,
yellowView.height |==| view.safeArea.height |/| 2 |-| 15
)
```
If OS version is below iOS 11, `view.safeArea.top` returns `view.top` internally.

![](./Images/iphone_x.gif)

Those are accessible safeArea properties.

```swift
extension UIView {
public var safeArea: UIViewSafeArea { get }
}

extension UIViewSafeArea {
public var top: MisterFusion { get }
public var right: MisterFusion { get }
public var left: MisterFusion { get }
public var bottom: MisterFusion { get }
public var height: MisterFusion { get }
public var width: MisterFusion { get }
public var leading: MisterFusion { get }
public var trailing: MisterFusion { get }
public var centerX: MisterFusion { get }
public var centerY: MisterFusion { get }
public var notAnAttribute: MisterFusion { get }
public var lastBaseline: MisterFusion { get }
public var firstBaseline: MisterFusion { get }
public var leftMargin: MisterFusion { get }
public var rightMargin: MisterFusion { get }
public var topMargin: MisterFusion { get }
public var bottomMargin: MisterFusion { get }
public var leadingMargin: MisterFusion { get }
public var trailingMargin: MisterFusion { get }
public var centerXWithinMargins: MisterFusion { get }
public var centerYWithinMargins: MisterFusion { get }
}
```

In ViewController, you can use `self.safeArea.top` and `self.safeArea.bottom`.

Greater than or equal to iOS 11, `self.safeArea.top` returns `self.view.safeAreaLayoutGuide.topAnchor`.
And `self.safeArea.bottom` returns, `self.view.safeAreaLayoutGuide.bottomAnchor`.

Less then or equal to iOS 10, `self.safeArea.top` returns 'self.topLayoutGuide.bottomAnchor'.
And `self.safeArea.bottom` returns, `self.bottomLayoutGuide.topAnchor`.

```swift
extension UIViewController {
public var safeArea: UIViewControllerSafeArea { get }
}

extension UIViewControllerSafeArea {
public var top: MisterFusion { get }
public var bottom: MisterFusion { get }
}
```

## For Objective-C

### Readonly Blocks

```objective-c
@interface MisterFusion : NSObject
//NSLayoutRelation
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull Equal)(MisterFusion * __nonnull);
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull LessThanOrEqual)(MisterFusion * __nonnull);
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull GreaterThanOrEqual)(MisterFusion * __nonnull);
//multiplier
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull Multiplier)(CGFloat);
//constant
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull Constant)(CGFloat);
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull NotRelatedEqualConstant)(CGFloat);
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull NotRelatedLessThanOrEqualConstant)(CGFloat);
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull NotRelatedGreaterThanOrEqualConstant)(CGFloat);
//@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull NotRelatedConstant)(CGFloat); (deprecated since 1.1.0, use NotRelatedEqualConstant)
//UILayoutPriority
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull Priority)(UILayoutPriority);
//UIUserInterfaceSizeClass for HorizontalSizeClass
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull HorizontalSizeClass)(UIUserInterfaceSizeClass);
//UIUserInterfaceSizeClass for VerticalSizeClass
@property (nonatomic, readonly, copy) MisterFusion * __nullable (^ __nonnull VerticalSizeClass)(UIUserInterfaceSizeClass);
//Identifier
@property (nonatomic, readonly, copy) MisterFusion * _Nullable (^ _Nonnull Identifier)(NSString * _Nonnull);
@end
```

#### UIView Category

```objective-c
- (NSLayoutConstraint * _Nullable)addLayoutConstraint:(MisterFusion * _Nonnull)misterFusion;
- (NSArray * _Nonnull)addLayoutConstraints:(NSArray * _Nonnull)misterFusions;
- (NSLayoutConstraint * _Nullable)addLayoutSubview:(UIView * _Nonnull)subview andConstraint:(MisterFusion * _Nonnull)misterFusion;
- (NSArray * _Nonnull)addLayoutSubview:(UIView * _Nonnull)subview andConstraints:(NSArray * _Nonnull)misterFusions;
- (NSLayoutConstraint * _Nullable)insertLayoutSubview:(UIView * _Nonnull)subview atIndex:(NSInteger)index andConstraint:(MisterFusion * _Nonnull)misterFusion;
- (NSArray * _Nonnull)insertLayoutSubview:(UIView * _Nonnull)subview atIndex:(NSInteger)index andConstraints:(NSArray * _Nonnull)misterFusions;
- (NSLayoutConstraint * _Nullable)insertLayoutSubview:(UIView * _Nonnull)subview belowSubview:(UIView * _Nonnull)siblingSubview andConstraint:(MisterFusion * _Nonnull)misterFusion;
- (NSArray * _Nonnull)insertLayoutSubview:(UIView * _Nonnull)subview belowSubview:(UIView * _Nonnull)siblingSubview andConstraints:(NSArray * _Nonnull)misterFusions;
- (NSLayoutConstraint * _Nullable)insertLayoutSubview:(UIView * _Nonnull)subview aboveSubview:(UIView * _Nonnull)siblingSubview andConstraint:(MisterFusion * _Nonnull)misterFusion;
- (NSArray * _Nonnull)insertLayoutSubview:(UIView * _Nonnull)subview aboveSubview:(UIView * _Nonnull)siblingSubview andConstraints:(NSArray * _Nonnull)misterFusions;
```

#### NSArray Category
```objective-c
@property (nonatomic, readonly, copy) NSArray * __nonnull (^ __nonnull FirstItem)(UIView * __nonnull);
@property (nonatomic, readonly, copy) NSArray * __nonnull (^ __nonnull FirstAttribute)(NSLayoutAttribute);
@property (nonatomic, readonly, copy) NSArray * __nonnull (^ __nonnull SecondItem)(UIView * __nonnull);
@property (nonatomic, readonly, copy) NSArray * __nonnull (^ __nonnull SecondAttribute)(NSLayoutAttribute);
@property (nonatomic, readonly, copy) NSArray * __nonnull (^ __nonnull Reration)(NSLayoutRelation);
```

You can get added `NSLayoutConstraint` with those properties.
This is a example.

```objective-c
NSLayoutConstraint *bottomConstraint = [self.view addLayoutSubview:view andConstraints:@[
view.Top .Constant(10.0f),
view.Right .Constant(-10.0f),
view.Left .Constant(10.0f),
view.Bottom.Constant(-10.0f)
]].FirstAttribute(NSLayoutAttributeBottom).firstObject;
```

You can use `Size Class` with `- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection`.

![](./Images/misterfusion.gif)

This is an example Regular, Compact size for iPhone6s+.

```objective-c
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
[self.redView removeConstraint:self.whiteViewWidthConstraint];
self.whiteViewWidthConstraint = [self.redView addLayoutConstraints:@[
self.whiteView.Width.Multiplier(0.5f).Constant(-10).VerticalSizeClass(UIUserInterfaceSizeClassRegular).HorizontalSizeClass(UIUserInterfaceSizeClassCompact),
self.whiteView.Width.Constant(-20).VerticalSizeClass(UIUserInterfaceSizeClassCompact).HorizontalSizeClass(UIUserInterfaceSizeClassRegular)
]].FirstAttribute(NSLayoutAttributeWidth).firstObject;
}
```

* A detail sample is [here](./Example/MisterFusionSample/MFViewController.m)

#### Safe Area

You can use `self.view.SafeAreaTop` and so on. This is supported Safe Area.

```objective-c
[self.view addLayoutConstraints:@[
yellowView.Top .Equal(redView.Bottom) .Constant(10.0f),
yellowView.Right .Equal(self.view.SafeAreaRight) .Constant(-10.0f),
yellowView.Left .Equal(self.view.SafeAreaLeft) .Constant(10.0f),
yellowView.Height.Equal(self.view.SafeAreaHeight).Multiplier(0.5f).Constant(-15.0f)
]];
```

If OS version is below iOS 11, `self.view.SafeAreaTop` returns `self.view.Top` internally.

![](./Images/iphone_x.gif)

Those are accessible safeArea properties.

```objective-c
// UIView
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaTop;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaRight;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaLeft;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaBottom;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaHeight;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaWidth;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaLeading;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaTrailing;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaCenterX;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaCenterY;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaNotAnAttribute;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaLastBaseline;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaFirstBaseline;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaLeftMargin;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaRightMargin;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaTopMargin;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaBottomMargin;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaLeadingMargin;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaTrailingMargin;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaCenterXWithinMargins;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaCenterYWithinMargins;
```

In ViewController, you can use `self.SafeAreaTop` and `self.SafeAreaBottom`.

Greater than or equal to iOS 11, `self.SafeAreaTop` returns `self.view.safeAreaLayoutGuide.topAnchor`.
And `self.SafeAreaBottom` returns, `self.view.safeAreaLayoutGuide.bottomAnchor`.

Less then or equal to iOS 10, `self.SafeAreaTop` returns 'self.topLayoutGuide.bottomAnchor'.
And `self.SafeAreaBottom` returns, `self.bottomLayoutGuide.topAnchor`.

```objective-c
// UIViewController
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaTop;
@property (nonatomic, readonly, strong) MisterFusion * _Nonnull SafeAreaBottom;
```

## Requirements

- Xcode 10.2 or greater
- iOS 8.0 or greater
- tvOS 10.0 or greater
- macOS 10.11 or greater

## Author

Taiki Suzuki, [email protected]

## License

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