級別: ★★☆☆☆
標籤:「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方法
奇舞週刊