iOS 经常使用布局方式之Constraint

级别: ★★☆☆☆
标签:「iOS AutoLayout」「iOS 自动布局」「NSLayoutConstraint」
做者: Xs·H
审校: QiShare团队php

沐灵洛 线下分享iOS UIButton根据内容自动布局时,有和前端同窗讨论到iOS的经常使用布局方式。讨论过程十分热闹,不容易记录,但做者认为讨论结果有必要记录一下,但愿能帮助到一些同窗。 做者将iOS经常使用布局方式概括为Frame、Autoresizing、Constraint、StackView和Masonry五种,并将逐一介绍。 本篇文章介绍Constraint。前端

Constraint相较于Autoresizing要更加灵活和强大,能够说是一种替代方案。Constraint的全称是NSLayoutConstraint,也常被称做AutoLayout,配合着Storyboard能够很是方便地构建页面。好比做者在上篇文章中没有实现的同级视图之间约束问题,使用NSLayoutConstraint将迎刃而解,而且不须要编写代码。在Storyboard中构建的约束关系以下。git

固然,开发者也可使用代码的形式利用NSLayoutConstraint布局视图。好比,做者在4等分视图的基础上,在浅灰色contentView上添加一个藏青色(cyanColor)的subView5,使其始终以固定的宽高居中显示,也就是实现下图中的效果。github

实现上述效果的代码以下。编程

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    UIView *subView5 = [[UIView alloc] initWithFrame:CGRectZero];
    subView5.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:.6];
    subView5.translatesAutoresizingMaskIntoConstraints = NO;
    [_contentView addSubview:subView5];
    
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:subView5 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:100.0];
    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:subView5 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:200.0];
    NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:subView5 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_contentView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:.0];
    NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:subView5 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_contentView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:.0];
    
    [_contentView addConstraints:@[widthConstraint, heightConstraint, centerXConstraint, centerYConstraint]];
}
复制代码

经过上述代码,看一下NSLayoutConstraint的用法。 首先,在使用代码利用NSLayoutConstraint布局视图时,要先指明该视图不被Autoresizing所控制(代码以下)。不然,会出现约束冲突的状况。bash

subView5.translatesAutoresizingMaskIntoConstraints = NO;
复制代码

而后,约束视图是经过“设定约束”和“添加约束”两个步骤来完成的。微信

设定约束

NSLayoutConstraint有标准的API来设定约束,以下。布局

/* Create constraints explicitly.  Constraints are of the form "view1.attr1 = view2.attr2 * multiplier + constant" 
 If your equation does not have a second view and attribute, use nil and NSLayoutAttributeNotAnAttribute.
 */
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
复制代码

通俗地解释一下上面的API:对view1的attr1属性和view2的attr2属性以relation这种关系和multiplier这种倍数进行c数值的约束。 好比,约束view1和view2等宽能够这样写:spa

[NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeWidth multiplier:1.0 constant:.0];
复制代码

其中,attr1和attr2都是从NSLayoutAttribute枚举中取值。3d

typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
    NSLayoutAttributeLeft = 1,
    NSLayoutAttributeRight,
    NSLayoutAttributeTop,
    NSLayoutAttributeBottom,
    NSLayoutAttributeLeading,
    NSLayoutAttributeTrailing,
    NSLayoutAttributeWidth,
    NSLayoutAttributeHeight,
    NSLayoutAttributeCenterX,
    NSLayoutAttributeCenterY,
    NSLayoutAttributeLastBaseline,
    NSLayoutAttributeBaseline NS_SWIFT_UNAVAILABLE("Use 'lastBaseline' instead") = NSLayoutAttributeLastBaseline,
    NSLayoutAttributeFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0),
    
    NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    
    NSLayoutAttributeNotAnAttribute = 0
};
复制代码

relation是从NSLayoutRelation枚举中取值。

typedef NS_ENUM(NSInteger, NSLayoutRelation) {
    NSLayoutRelationLessThanOrEqual = -1,
    NSLayoutRelationEqual = 0,
    NSLayoutRelationGreaterThanOrEqual = 1,
};
复制代码

综上,在理解API各参数含义的基础上将会更容易读懂上述subView5的4个约束。

添加约束

先看一下例子中添加约束的代码,以下。

[_contentView addConstraints:@[widthConstraint, heightConstraint, centerXConstraint, centerYConstraint]];
复制代码

做者将4个约束都添加到了contentView上面,固然,运行效果证实这样添加没有问题。但有的同窗问道:“ 由于subView5的位置被约束到了contentView上,因此centerXConstraint和centerYConstraint被添加到contentView上是容易被理解的,可是widthConstraint和heightConstraint只和subView5有关系,为何也添加到了contentView上,不是应该添加到subView5上吗?”。是的,按照这种说法,widthConstraint和heightConstraint添加到subView5的确更容易理解,因而做者作了以下修改。

[subView5 addConstraints:@[widthConstraint, heightConstraint]];
[_contentView addConstraints:@[centerXConstraint, centerYConstraint]];
复制代码

从修改后的运行效果看也是没有问题的。之因此将4个constraint都添加到了contentView上,是由于**无论是对哪一个视图的约束,只要添加到该视图或者该视图的父视图以及更高层级的父视图上,都是没有问题的。**因此,在编程中,开发者经常会将多个约束统一添加到某个比较靠近用户的父视图上。

关于本篇文章的具体实现细节能够在QiLayoutDemo中查看。


小编微信:可加并拉入《QiShare技术交流群》。

关注咱们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)

推荐文章:
iOS UIButton根据内容自动布局
iOS 指定初始化方法
UIView中的hitTest方法
奇舞周刊

相关文章
相关标签/搜索