MisterFusion 5.0.0

MisterFusion 5.0.0

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布上次发布2019年9月
SPM支持SPM

Taiki Suzuki维护。



MisterFusion

Platform Language Version Carthage compatible License Build Status

MisterFusion使得在Swift和Objective-C代码中使用AutoLayout更加简便。

特性

  • 简洁的语法
  • 支持Swift和Objective-C
  • 支持尺寸类
  • 支持Swift5
  • 支持Swift4(至4.0.1)
  • 支持SafeArea🎉(自2.3.1以来支持Swift3.2,自3.1.0以来支持Swift4)
  • 支持iOS
  • 支持tvOS(自3.2.0以来)
  • 支持macOS(自4.0.0以来)

MisterFusion的Swift代码

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

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),
])

Objective-C的MisterFusion代码

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)
]];

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]
]];

示例布局

如果您想实现像上面图片那样的布局,只需这段代码即可。

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
)

安装

CocoaPods

您可以通过CocoaPods安装MisterFusion。如果您安装了0.39.0或更高版本的CocoaPods,可以这样添加到您的Podfile中

pod 'MisterFusion'

此外,像这样导入 MisterFusion

Swift
import MisterFusion
Objective-C
#import <MisterFusion/MisterFusion-Swift.h>

Carthage

如果您正在使用 Carthage,只需将MristerFusion添加到您的Cartfile

github "szk-atmosphere/MisterFusion"

请确保将MisterFusion.framework添加到"链接框架和库"以及"复制框架"构建阶段。

高级设置

您可以设置乘数常数优先级,如下所示。(这与第一个示例中的实现相同。)

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

[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

运算符

  • |==||<=||>=| ... NSLayoutRelation以及固定的高度和宽度
  • |*||/| ... 乘数
  • |+||-| ... 常数
  • |<>| ... UILayoutPriority
  • <|> ... UIUserInterfaceSizeClass针对垂直SizeClass
  • <-> ... UIUserInterfaceSizeClass针对水平SizeClass
  • -=- ... 标识符

UIView 扩展

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]

数组扩展

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]

您可以使用这些函数获取额外的 NSLayoutConstraint。以下是一个示例。

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

您可以使用 Size Classfunc traitCollectionDidChange(previousTraitCollection: UITraitCollection?)

以下是为 iPhone6s+ 准备的常规、紧凑尺寸示例。

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
}
  • 详细信息请访问 此处

安全区域

您可以使用 view.safeArea.top 等。这是支持安全区域的方法。

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
)

如果操作系统版本低于 iOS 11,则内部 view.safeArea.top 返回 view.top

这些是可访问的安全区域属性。

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 }
}

在 ViewController 中,您可以使用 self.safeArea.topself.safeArea.bottom

从 iOS 11 开始,self.safeArea.top 返回 self.view.safeAreaLayoutGuide.topAnchor。而 self.safeArea.bottom 返回 self.view.safeAreaLayoutGuide.bottomAnchor

在 iOS 10 或更早版本中,self.safeArea.top 返回 'self.topLayoutGuide.bottomAnchor'。而 self.safeArea.bottom 返回 self.bottomLayoutGuide.topAnchor

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

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

针对 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 类别

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

NSArray 类别

@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);

您可以使用这些属性获取附加的 NSLayoutConstraint。以下是一个示例。

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;

您可以使用 Size Class- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection

以下是为 iPhone6s+ 准备的常规、紧凑尺寸示例。

- (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;
}
  • 详细信息请参阅 此处

安全区域

您可以使用 self.view.SafeAreaTop 等属性。这是支持的安全区域。

[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)
]];

如果操作系统版本低于 iOS 11,则 self.view.SafeAreaTop 将内部返回 self.view.Top

这些是可访问的安全区域属性。

// 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;

在 ViewController 中,您可以使用 self.SafeAreaTopself.SafeAreaBottom

从 iOS 11 或更高版本开始,self.SafeAreaTop 返回 self.view.safeAreaLayoutGuide.topAnchor,而 self.SafeAreaBottom 返回 self.view.safeAreaLayoutGuide.bottomAnchor

对于 iOS 10 或更低版本,self.SafeAreaTop 返回 'self.topLayoutGuide.bottomAnchor',而 self.SafeAreaBottom 返回 'self.bottomLayoutGuide.topAnchor'。

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

需求

  • Xcode 10.2 或更高版本
  • iOS 8.0 或更高版本
  • tvOS 10.0 或更高版本
  • macOS 10.11 或更高版本

作者

Taiki Suzuki,[email protected]

许可证

MisterFusion 基于 MIT 许可证。有关更多信息,请参阅 LICENSE 文件。