Auto Layout
Auto Layout 即自動(dòng)布局,在iOS6引入,不同于frame框架式的布局,自動(dòng)布局根據(jù)視圖間的相對(duì)約束來確定視圖位置與大小,使視圖得以動(dòng)態(tài)的適應(yīng)位置與大小的變化,匹配不同尺寸的設(shè)備,從而節(jié)省大量設(shè)置或更新視圖位置與大小的代碼。自動(dòng)布局涉及:NSLayoutConstraint(布局約束)、NSLayoutAnchor(布局錨)、UILayoutGuide(布局占位)、SizeClasses(屏幕適配)、Constraints in Interface Builder(故事板約束)等。
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 200)];
view.backgroundColor = [UIColor greenColor];
[self.view addSubview:view];
}
正常情況下,顯示沒有問題:
但當(dāng)設(shè)備發(fā)生旋轉(zhuǎn)時(shí),問題便產(chǎn)生了:
這顯然不是我們想看到的效果,如果使用約束進(jìn)行布局:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view2 = [[UIView alloc]initWithFrame:CGRectZero];
view2.backgroundColor = [UIColor greenColor];
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view2];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:view2
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:view2
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:view2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:view2
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200];
[self.view addConstraint:topConstraint];
[self.view addConstraint:leftConstraint];
[self.view addConstraint:widthConstraint];
[self.view addConstraint:heightConstraint];
}
正常情況下,顯示沒有問題:
當(dāng)設(shè)備發(fā)生旋轉(zhuǎn)時(shí),顯示也是沒有問題:
當(dāng)然現(xiàn)在添加約束的代碼仍舊非常繁瑣,寫起來仍舊讓人想在心里默默的數(shù)著羊駝,但是該看的api還是要看,誰讓我們要去學(xué)習(xí),要去認(rèn)知呢。
UIView (UIConstraintBasedCompatibility) - 基于約束的兼容性
@property(nonatomic) BOOL translatesAutoresizingMaskIntoConstraints API_AVAILABLE(ios(6.0));
屬性描述 :一個(gè)布爾值,如果此屬性的值為YES,系統(tǒng)將基于視圖的大小和位置的掩碼為視圖轉(zhuǎn)換為自動(dòng)布局約束,而約束完全指定了視圖的大小和位置,因此,在不引入沖突的情況下,無法添加其他約束來修改此大小或位置。如果要使用“Auto Layout”動(dòng)態(tài)計(jì)算視圖的大小和位置,則必須將此屬性設(shè)置為NO,然后為視圖提供一組無歧義、無沖突的約束。默認(rèn)情況下,對(duì)于以編程方式創(chuàng)建的任何視圖,該屬性都設(shè)置為YES。如果在Interface Builder中添加視圖,系統(tǒng)會(huì)自動(dòng)將此屬性設(shè)置為NO。這個(gè)擴(kuò)展于UIView中的屬性也就是我們使用自動(dòng)布局設(shè)置約束的先決條件了。
NSLayoutConstraint - 布局約束
NSLayoutConstraint,描述一條約束的對(duì)象,基于約束的布局系統(tǒng)必須滿足的兩個(gè)用戶界面對(duì)象之間的關(guān)系。每個(gè)約束都是一個(gè)線性方程,格式如下:
item1.attribute1 = multiplier × item2.attribute2 + constant
在這個(gè)等式中,attribute1和attribute2是Auto Layout在解決這些約束時(shí)可以調(diào)整的變量。其他值在創(chuàng)建約束時(shí)定義。例如,如果定義兩個(gè)按鈕的相對(duì)位置,可能這樣描述 “第二個(gè)按鈕的前緣應(yīng)該在第一個(gè)按鈕的后緣之后8個(gè)點(diǎn)。” 此關(guān)系的線性方程如下所示(在英語等從左到右的語言中,正值向右移動(dòng)):
button2.leading = 1.0 × button1.trailing + 8.0
Auto Layout然后修改指定的前邊和后緣的值,直到公式的兩邊相等。注意,Auto Layout不會(huì)簡單地將該等式右側(cè)的值指定給左側(cè)。相反,系統(tǒng)可以根據(jù)需要修改其中一個(gè)屬性或兩個(gè)屬性來解決此約束。
約束是表達(dá)式(而不是賦值運(yùn)算符)這一事實(shí)意味著可以根據(jù)需要切換方程中項(xiàng)目的順序,以更清楚地表達(dá)所需的關(guān)系。但是,如果切換順序,還必須反轉(zhuǎn)乘數(shù)和常數(shù)。例如,以下兩個(gè)等式產(chǎn)生相同的約束:
button2.leading = 1.0 × button1.trailing + 8.0
button1.trailing = 1.0 × button2.leading - 8.0
一個(gè)有效的布局被定義為一組約束,并且只有一個(gè)可能的解決方案。有效的布局也被稱為無歧義、無沖突的布局。具有多個(gè)解決方案的約束是不明確的。沒有有效解決方案的約束是沖突的。
此外,約束并不局限于等式關(guān)系。它們還可以使用大于或等于(>=)或小于或等于(<=)來描述這兩個(gè)屬性之間的關(guān)系。約束的priority(優(yōu)先級(jí))也在1到1000之間,priority為1000的約束是必要約束,所有低于1000的priority都是可選約束,默認(rèn)情況下,所有約束都是必需的(priority = 1000)。
在求解完所需的約束條件后,Auto Layout將嘗試按照從高到低的優(yōu)先級(jí)順序求解所有可選約束條件。如果它不能解決一個(gè)可選的約束,它就會(huì)嘗試盡可能接近期望的結(jié)果,然后轉(zhuǎn)向下一個(gè)約束。這種不相等、相等和優(yōu)先級(jí)的組合提供了很大的靈活性和權(quán)力。通過組合多個(gè)約束,可以定義隨著用戶界面中元素的大小和位置變化而動(dòng)態(tài)適應(yīng)的布局。
NSLayoutConstraint的常用屬性
@property CGFloat constant;
屬性描述 : 加入到參與約束的第二個(gè)屬性的乘數(shù)上的常數(shù)。即item1.attribute1 = multiplier × item2.attribute2 + constant中的constant。與其他屬性不同,該常量可以在約束創(chuàng)建后修改。 在現(xiàn)有約束上設(shè)置常量比刪除約束并添加一個(gè)與舊約束完全相同的新約束要好得多。
@property UILayoutPriority priority;
屬性描述 :約束的優(yōu)先級(jí)。
- 系統(tǒng)提供的約束優(yōu)先級(jí):
//必要的約束。不要指定超過此數(shù)字的布局約束優(yōu)先級(jí)。(最大優(yōu)先級(jí))
static const UILayoutPriority UILayoutPriorityRequired API_AVAILABLE(ios(6.0)) = 1000;
//按鈕阻止壓縮其內(nèi)容的優(yōu)先級(jí)。(可作為中位優(yōu)先級(jí))
static const UILayoutPriority UILayoutPriorityDefaultHigh API_AVAILABLE(ios(6.0)) = 750;
//這可能是拖動(dòng)調(diào)整窗口最終場(chǎng)景大小的適當(dāng)優(yōu)先級(jí)。
static const UILayoutPriority UILayoutPriorityDragThatCanResizeScene API_AVAILABLE(macCatalyst(13.0)) = 510;
//這是窗口的場(chǎng)景希望保持相同大小的優(yōu)先級(jí)。一般來說,在這種優(yōu)先級(jí)下進(jìn)行約束是不合適的。
static const UILayoutPriority UILayoutPrioritySceneSizeStayPut API_AVAILABLE(macCatalyst(13.0)) = 500;
//這是分屏視圖分隔符被拖動(dòng)時(shí)的優(yōu)先級(jí)。它不會(huì)調(diào)整窗口場(chǎng)景的大小。
static const UILayoutPriority UILayoutPriorityDragThatCannotResizeScene API_AVAILABLE(macCatalyst(13.0)) = 490;
//這是按鈕水平擁抱其內(nèi)容的優(yōu)先級(jí)。(可作為低位優(yōu)先級(jí))
static const UILayoutPriority UILayoutPriorityDefaultLow API_AVAILABLE(ios(6.0)) = 250;
//發(fā)送-[UIView systemLayoutSizeFittingSize:]時(shí),將計(jì)算與目標(biāo)大小(參數(shù))最接近的大小。
//UILayoutPriorityFittingSizeLevel是視圖希望符合該計(jì)算中目標(biāo)大小的優(yōu)先級(jí)。
//很低。一般來說,在這個(gè)優(yōu)先級(jí)上進(jìn)行約束是不合適的。
static const UILayoutPriority UILayoutPriorityFittingSizeLevel API_AVAILABLE(ios(6.0)) = 50;
@property (getter=isActive) BOOL active API_AVAILABLE(macos(10.10), ios(8.0));
屬性描述 :約束的活動(dòng)狀態(tài)。可以通過更改此屬性來激活或停用約束。只有活動(dòng)約束會(huì)影響計(jì)算的布局。對(duì)于新創(chuàng)建的約束,默認(rèn)情況下active屬性是NO。激活或停用約束會(huì)在視圖上調(diào)用addConstraint:和removeconconstraint:,在為ios8.0或更高版本開發(fā)時(shí),應(yīng)該使用這個(gè)屬性,而不是直接調(diào)用addConstraint:或removeconconstraint:。
@property (nullable, readonly, assign) id firstItem;
屬性描述 :要添加約束的對(duì)象。
@property (nullable, readonly, assign) id secondItem;
屬性描述 :要添加約束對(duì)象的參照對(duì)象。
@property (readonly) NSLayoutAttribute firstAttribute;
屬性描述 :添加約束的對(duì)象的約束屬性。
@property (readonly) NSLayoutAttribute secondAttribute;
屬性描述 :添加約束時(shí),作為約束對(duì)象的參照對(duì)象的約束屬性。
NSLayoutConstraint的常用函數(shù)
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c API_AVAILABLE(macos(10.7), ios(6.0), tvos(9.0));
函數(shù)描述:創(chuàng)建一個(gè)約束,該約束定義給定視圖的指定屬性之間的關(guān)系。約束表示形式為view1.attr1<relation> = multiplier × view2.attr2 + c 的線性方程。如果要表達(dá)的約束沒有第二個(gè)視圖和屬性,請(qǐng)使用nil和NSLayoutAttributeNotAnAttribute。
如果此方法用于創(chuàng)建無效約束,則該方法將引發(fā)NSInvalidArgumentException異常。例如這種我們無法描述的約束:view1.top = 0.0 x nil.NSLayoutAttributeNotAnAttribute + 200.0(視圖1的頂部等于0倍的不知道哪個(gè)視圖的哪個(gè)布局屬性加200,你什么都不知道,啊~,我崩潰了)或view1.top = 1.0 x view2.height + 20.0(視圖1的頂部等于1倍的視圖2的高度加20,我倆的確切關(guān)系是什么啊,啊~,我崩潰了)。
參數(shù) :
view1 :約束左側(cè)的視圖(要約束的視圖)。
attr1 :約束左側(cè)的視圖屬性。
relation :約束的左側(cè)和右側(cè)之間的關(guān)系。
view2 :約束右側(cè)的視圖(參照的視圖)。
attr2 :約束右側(cè)的視圖屬性。
multiplier:常數(shù)乘以約束右側(cè)的屬性,作為獲取修改屬性的一部分。
c:約束右側(cè)的乘以屬性值以后,添加約束值生成最終修改的屬性的常量。
返回值 : 用指定的關(guān)系、屬性、乘數(shù)和常量將兩個(gè)提供的視圖關(guān)聯(lián)起來的約束對(duì)象。
- (void)addConstraint:(NSLayoutConstraint *)constraint API_AVAILABLE(ios(6.0));
函數(shù)描述 :在調(diào)用函數(shù)的視圖或其子視圖的布局上添加約束。約束必須只涉及調(diào)用函數(shù)的視圖范圍內(nèi)的視圖。具體來說,涉及的任何視圖必須是調(diào)用函數(shù)的視圖本身,或者是調(diào)用函數(shù)的視圖的子視圖。添加到視圖中的約束被稱為該視圖持有的約束。在評(píng)估約束時(shí)使用的坐標(biāo)系統(tǒng)是持有約束的視圖的坐標(biāo)系統(tǒng)。
在為ios8.0或更高版本開發(fā)時(shí),將約束的active屬性設(shè)置為YES,而不是直接調(diào)用addConstraint:方法。active屬性會(huì)自動(dòng)在正確的視圖中添加和刪除約束。
參數(shù) :
constraint :要添加到視圖中的約束。約束只能引用視圖本身或其子視圖。
- (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints API_AVAILABLE(ios(6.0));
函數(shù)描述:在調(diào)用函數(shù)的視圖或其子視圖的布局上添加多個(gè)約束。所有約束必須只涉及調(diào)用函數(shù)的視圖范圍內(nèi)的視圖。具體來說,涉及的任何視圖必須是調(diào)用函數(shù)的視圖本身,或者是調(diào)用函數(shù)的視圖的子視圖。添加到視圖中的約束稱為該視圖所持有。計(jì)算每個(gè)約束時(shí)使用的坐標(biāo)系是包含該約束的視圖的坐標(biāo)系。
在為iOS8.0或更高版本開發(fā)時(shí),可以使用NSLayoutConstraint類的activateConstraint:方法,而不是直接調(diào)用addConstraints:方法。activateConstraints:方法自動(dòng)將約束添加到正確的視圖中。
參數(shù) :
constraints : 要添加到視圖中的約束數(shù)組。所有約束只能引用視圖本身或其子視圖。
+ (void)activateConstraints:(NSArray<NSLayoutConstraint *> *)constraints API_AVAILABLE(macos(10.10), ios(8.0));
函數(shù)描述:激活指定數(shù)組中的每個(gè)約束。這個(gè)方便的方法提供了一種簡單的方法來通過一次調(diào)用激活一組約束。此方法的效果與將每個(gè)約束的active屬性設(shè)置為YES相同。通常,使用此方法比單獨(dú)激活每個(gè)約束更有效。
參數(shù):
constraints : 要激活的一組約束。
+ (void)deactivateConstraints:(NSArray<NSLayoutConstraint *> *)constraints API_AVAILABLE(macos(10.10), ios(8.0));
函數(shù)描述:這是一種方便的方法,提供了一種簡單的方法來通過一次調(diào)用禁用一組約束。此方法的效果與將每個(gè)約束的active屬性設(shè)置為NO相同。通常,使用此方法比單獨(dú)禁用每個(gè)約束更有效。
參數(shù):
constraints : 要禁用的一組約束。
+ (NSArray<NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *, id> *)metrics views:(NSDictionary<NSString *, id> *)views API_AVAILABLE(macos(10.7), ios(6.0), tvos(9.0));
函數(shù)描述 :創(chuàng)建由ASCII技術(shù)(如可視格式字符串)描述的約束。
參數(shù) :
format : 約束的格式規(guī)范。
opts : 描述視覺格式字符串中所有對(duì)象的屬性和布局方向的選項(xiàng)。
metrics : 出現(xiàn)在可視格式字符串中的常量字典。字典的鍵必須是視覺格式字符串中使用的字符串值。它們的值必須是NSNumber對(duì)象。
views : 以可視格式字符串顯示的視圖字典。鍵必須是視覺格式字符串中使用的字符串值,而值必須是視圖對(duì)象。
返回值 : 一個(gè)約束數(shù)組,組合在一起,表示所提供的視圖與其父視圖之間的約束,如可視化格式字符串所述。約束的返回順序與在可視格式字符串中指定的順序相同。
注 : 字符串約束的格式規(guī)范規(guī)則:
| 其含義表示父視圖
- 其含義表示距離
V: 其含義表示垂直
H: 其含義表示水平
>= 其含義表示視圖間距、寬度和高度必須大于或等于某個(gè)值
<= 其含義表示視圖間距、寬度和高度必須小宇或等于某個(gè)值
== 其含義表示視圖間距、寬度或者高度必須等于某個(gè)值
@ 其含義表示>=、<=、== 其值限制最大設(shè)為1000
[view(>=200@300)] 其含義表示視圖的寬度為至少為200 不能超過 300
|-[view]-| 其含義表示視圖處在父視圖的左右邊緣內(nèi)
|-[view] 其含義表示視圖處在父視圖的左邊緣
|[view] 其含義表示視圖和父視圖左邊對(duì)齊
|-50.0-[view]-50.0-| 其含義表示離父視圖左右間距50
[view(200.0)] 其含義表示視圖寬度為 200.0
V:[view2(200.0)] 其含義表示視圖高度為 200.0
可以使用字符串來描述視圖間的約束,是不是很神奇,而且代碼設(shè)置約束的代碼是不是就減少了:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view2 = [[UIView alloc]initWithFrame:CGRectZero];
view2.backgroundColor = [UIColor greenColor];
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view2];
//描述view2距其父視圖頂部為0
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0.0-[view2](0.0)" options:0 metrics:nil views:@{@"view2": view2}]];
//描述view2距其父視圖左右為0
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-0.0-[view2]-0.0-|" options:0 metrics:nil views:@{@"view2": view2}]];
//描述view2高度為200
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[view2(200.0)]" options:0 metrics:nil views:@{@"view2": view2}]];
}
效果如圖 :
然鵝,但凡有一條約束使用字符串描述錯(cuò)誤,IOS就會(huì)讓你NSInvalidArgumentException異常了解一下,坑爹呢啊,我要掀桌了!!
NSLayoutAttribute - 布局屬性
NSLayoutAttribute,表示可視對(duì)象的一部分,應(yīng)該用于獲取約束的值。
typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
//對(duì)象對(duì)齊矩形的左側(cè)
NSLayoutAttributeLeft = 1,
//對(duì)象對(duì)齊矩形的右側(cè)
NSLayoutAttributeRight,
//對(duì)象對(duì)齊矩形的頂部
NSLayoutAttributeTop,
//對(duì)象對(duì)齊矩形的底部
NSLayoutAttributeBottom,
//對(duì)象對(duì)齊矩形的前緣
NSLayoutAttributeLeading,
//對(duì)象對(duì)齊矩形的后緣
NSLayoutAttributeTrailing,
//對(duì)象對(duì)齊矩形的寬度
NSLayoutAttributeWidth,
//對(duì)象對(duì)齊矩形的高度
NSLayoutAttributeHeight,
//沿對(duì)象對(duì)齊矩形x軸的中心
NSLayoutAttributeCenterX,
//沿對(duì)象對(duì)齊矩形的y軸的中心
NSLayoutAttributeCenterY,
//對(duì)象的基線。對(duì)于具有多行文本的對(duì)象,這是最下面一行文本的基線。
NSLayoutAttributeLastBaseline,
#if TARGET_OS_IPHONE
NSLayoutAttributeBaseline NS_SWIFT_UNAVAILABLE("Use 'lastBaseline' instead") = NSLayoutAttributeLastBaseline,
#else
NSLayoutAttributeBaseline = NSLayoutAttributeLastBaseline,
#endif
//對(duì)象的基線。對(duì)于具有多行文本的對(duì)象,這是最上面一行文本的基線
NSLayoutAttributeFirstBaseline API_AVAILABLE(macos(10.11), ios(8.0)),
#if TARGET_OS_IPHONE
//對(duì)象的左邊距。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義
NSLayoutAttributeLeftMargin API_AVAILABLE(ios(8.0)),
//對(duì)象的右邊距。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義
NSLayoutAttributeRightMargin API_AVAILABLE(ios(8.0)),
//對(duì)象的上邊距。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義。
NSLayoutAttributeTopMargin API_AVAILABLE(ios(8.0)),
//對(duì)象的下邊距。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義。
NSLayoutAttributeBottomMargin API_AVAILABLE(ios(8.0)),
//對(duì)象的前緣邊距。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義
NSLayoutAttributeLeadingMargin API_AVAILABLE(ios(8.0)),
//對(duì)象的后緣邊距。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義
NSLayoutAttributeTrailingMargin API_AVAILABLE(ios(8.0)),
//對(duì)象左右邊距之間沿x軸的中心。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義。
NSLayoutAttributeCenterXWithinMargins API_AVAILABLE(ios(8.0)),
//對(duì)象上下邊距之間沿y軸的中心。對(duì)于UIView對(duì)象,頁邊距由其layoutMargins屬性定義。
NSLayoutAttributeCenterYWithinMargins API_AVAILABLE(ios(8.0)),
#endif
//占位符值,用于指示約束的第二項(xiàng)和第二個(gè)屬性在任何計(jì)算中都不使用。創(chuàng)建將常量指定給屬性的約束時(shí),請(qǐng)使用此值。
//例如,item1.height>=40。如果約束只有一個(gè)項(xiàng),請(qǐng)將第二項(xiàng)設(shè)置為nil,并將第二個(gè)屬性設(shè)置為NSLayoutAttributeNotAnAttribute
NSLayoutAttributeNotAnAttribute = 0
};
NSLayoutRelation - 布局關(guān)系
typedef NS_ENUM(NSInteger, NSLayoutRelation) {
//約束要求第一個(gè)屬性小于或等于修改后的第二個(gè)屬性。
NSLayoutRelationLessThanOrEqual = -1,
//約束要求第一個(gè)屬性與修改后的第二個(gè)屬性完全相等。
NSLayoutRelationEqual = 0,
//約束要求第一個(gè)屬性大于或等于修改后的第二個(gè)屬性。
NSLayoutRelationGreaterThanOrEqual = 1,
};
NSLayoutAnchor - 布局錨
使用流式 API 創(chuàng)建布局約束對(duì)象的工廠類。使用這些約束以編程方式使用 Auto Layout 定義布局。不要直接創(chuàng)建 NSLayoutConstraint 對(duì)象,而是從一個(gè)你想要約束的UIView、 NSView或者UILayoutGuide對(duì)象開始,然后選擇一個(gè)對(duì)象的錨定屬性。這些屬性對(duì)應(yīng)于 Auto Layout 中使用的主要 NSLayoutAttribute 值,并提供一個(gè)適當(dāng)?shù)腘SLayoutAnchor子類來創(chuàng)建該屬性的約束。使用錨定的方法來構(gòu)造約束。
NSLayoutAnchor類比直接使用NSLayoutConstraint的API創(chuàng)建約束代碼更簡潔,更容易閱讀。NSLayoutAttribute的子類提供了額外的類型檢查,在一定程度上防止創(chuàng)建無效的約束,但仍舊需要仔細(xì)檢查約束,以避免無效約束造成崩潰。
NSLayoutAnchor的常用函數(shù)
- (NSLayoutConstraint *)constraintEqualToAnchor:(NSLayoutAnchor<AnchorType> *)anchor __attribute__((warn_unused_result));
函數(shù)描述 :返回一條約束,此方法定義兩個(gè)錨點(diǎn)相等(=)的關(guān)系。其中,調(diào)用此方法的錨點(diǎn)表示要布局的錨點(diǎn),參數(shù)錨點(diǎn)表示布局要參照的錨點(diǎn)。
參數(shù) :
anchor : 一個(gè)來自UIView、NSView或UILayoutGuide對(duì)象的布局錨。用來作為參照錨點(diǎn)。你必須使用NSLayoutAnchor的一個(gè)子類來匹配當(dāng)前的錨點(diǎn)。例如,如果在一個(gè)NSLayoutXAxisAnchor對(duì)象上調(diào)用這個(gè)方法,這個(gè)參數(shù)必須是另一個(gè)NSLayoutXAxisAnchor。
返回值 : 一個(gè)NSLayoutConstraint對(duì)象,它定義了兩個(gè)布局錨點(diǎn)之間的相等關(guān)系。
- (NSLayoutConstraint *)constraintEqualToAnchor:(NSLayoutAnchor<AnchorType> *)anchor constant:(CGFloat)c __attribute__((warn_unused_result));
函數(shù)描述 :返回一條約束,此方法定義第一個(gè)錨點(diǎn)等于(=)第二個(gè)錨點(diǎn)加上常量偏移量的關(guān)系。其中,調(diào)用此方法的錨點(diǎn)表示要布局的錨點(diǎn),參數(shù)錨點(diǎn)表示布局要參照的錨點(diǎn)。值c表示恒定偏移量。
參數(shù) :
anchor : 一個(gè)來自UIView、NSView或UILayoutGuide對(duì)象的布局錨。用來作為參照錨點(diǎn)。你必須使用NSLayoutAnchor的一個(gè)子類來匹配當(dāng)前的錨點(diǎn)。例如,如果在一個(gè)NSLayoutXAxisAnchor對(duì)象上調(diào)用這個(gè)方法,這個(gè)參數(shù)必須是另一個(gè)NSLayoutXAxisAnchor。
c : 約束的恒定偏移量。
返回值 :一個(gè) NSLayoutConstraint對(duì)象,它定義了兩個(gè)布局錨點(diǎn)之間的相等關(guān)系與一個(gè)恒定偏移量。
- (NSLayoutConstraint *)constraintGreaterThanOrEqualToAnchor:(NSLayoutAnchor<AnchorType> *)anchor __attribute__((warn_unused_result));
函數(shù)描述 :返回一條約束,此方法定義第一個(gè)錨點(diǎn)大于等于(>=)第二個(gè)錨點(diǎn)。其中,調(diào)用此方法的錨點(diǎn)表示要布局的錨點(diǎn),參數(shù)錨點(diǎn)表示布局要參照的錨點(diǎn)。
參數(shù) :
anchor : 一個(gè)來自UIView、NSView或UILayoutGuide對(duì)象的布局錨。用來作為參照錨點(diǎn)。你必須使用NSLayoutAnchor的一個(gè)子類來匹配當(dāng)前的錨點(diǎn)。例如,如果在一個(gè)NSLayoutXAxisAnchor對(duì)象上調(diào)用這個(gè)方法,這個(gè)參數(shù)必須是另一個(gè)NSLayoutXAxisAnchor。
返回值 :一個(gè) NSLayoutConstraint對(duì)象,它定義了布局錨點(diǎn)大于或等于參照錨點(diǎn)。
- (NSLayoutConstraint *)constraintGreaterThanOrEqualToAnchor:(NSLayoutAnchor<AnchorType> *)anchor constant:(CGFloat)c __attribute__((warn_unused_result));
函數(shù)描述 :返回一條約束,此方法定義第一個(gè)錨點(diǎn)大于或等于(>=)第二個(gè)錨點(diǎn)加上常量偏移量。其中,調(diào)用此方法的錨點(diǎn)表示要布局的錨點(diǎn),參數(shù)錨點(diǎn)表示布局要參照的錨點(diǎn)。
參數(shù) :
anchor : 一個(gè)來自UIView、NSView或UILayoutGuide對(duì)象的布局錨。用來作為參照錨點(diǎn)。你必須使用NSLayoutAnchor的一個(gè)子類來匹配當(dāng)前的錨點(diǎn)。例如,如果在一個(gè)NSLayoutXAxisAnchor對(duì)象上調(diào)用這個(gè)方法,這個(gè)參數(shù)必須是另一個(gè)NSLayoutXAxisAnchor。
c : 約束的恒定偏移量。
返回值 :一個(gè) NSLayoutConstraint對(duì)象,它定義了兩個(gè)布局錨點(diǎn)之間大于或等于(>=)的關(guān)系與一個(gè)恒定偏移量。
- (NSLayoutConstraint *)constraintLessThanOrEqualToAnchor:(NSLayoutAnchor<AnchorType> *)anchor __attribute__((warn_unused_result));
函數(shù)描述 :返回一條約束,此方法定義第一個(gè)錨點(diǎn)小于于或等于(<=)第二個(gè)錨點(diǎn)。其中,調(diào)用此方法的錨點(diǎn)表示要布局的錨點(diǎn),參數(shù)錨點(diǎn)表示布局要參照的錨點(diǎn)。
參數(shù) :
anchor : 一個(gè)來自UIView、NSView或UILayoutGuide對(duì)象的布局錨。用來作為參照錨點(diǎn)。你必須使用NSLayoutAnchor的一個(gè)子類來匹配當(dāng)前的錨點(diǎn)。例如,如果在一個(gè)NSLayoutXAxisAnchor對(duì)象上調(diào)用這個(gè)方法,這個(gè)參數(shù)必須是另一個(gè)NSLayoutXAxisAnchor。
返回值 :一個(gè) NSLayoutConstraint對(duì)象,它定義了布局錨點(diǎn)小于或等于參照錨點(diǎn)。
- (NSLayoutConstraint *)constraintLessThanOrEqualToAnchor:(NSLayoutAnchor<AnchorType> *)anchor constant:(CGFloat)c __attribute__((warn_unused_result));
函數(shù)描述 :返回一條約束,此方法定義第一個(gè)錨點(diǎn)小于或等于(<=)第二個(gè)錨點(diǎn)加上常量偏移量。其中,調(diào)用此方法的錨點(diǎn)表示要布局的錨點(diǎn),參數(shù)錨點(diǎn)表示布局要參照的錨點(diǎn)。
參數(shù) :
anchor : 一個(gè)來自UIView、NSView或UILayoutGuide對(duì)象的布局錨。用來作為參照錨點(diǎn)。你必須使用NSLayoutAnchor的一個(gè)子類來匹配當(dāng)前的錨點(diǎn)。例如,如果在一個(gè)NSLayoutXAxisAnchor對(duì)象上調(diào)用這個(gè)方法,這個(gè)參數(shù)必須是另一個(gè)NSLayoutXAxisAnchor。
c : 約束的恒定偏移量。
返回值 :一個(gè) NSLayoutConstraint對(duì)象,它定義了兩個(gè)布局錨點(diǎn)之間小于或等于(<=)的關(guān)系與一個(gè)恒定偏移量。
小結(jié) :上面的方法分別定義了錨點(diǎn)間等于(=)、大于等于(>=)、小于等于(<=)的關(guān)系,以及是否有偏移量參與錨點(diǎn)間的定位,偏移量的數(shù)值均以點(diǎn)為單位測(cè)量。根據(jù)布局錨點(diǎn)的類型,偏移量的值可以以不同的方式進(jìn)行解釋:
對(duì)于NSLayoutXAxisAnchor對(duì)象,當(dāng)使用leadingAnchor(前緣)或trailingAnchor(后緣)時(shí),偏移量增加,錨點(diǎn)定位的視圖后移,偏移量減少,錨點(diǎn)定位的視圖前移。當(dāng)使用leftAnchor(左側(cè))或rightAnchor(右側(cè))時(shí),偏移量增加,錨點(diǎn)定位的視圖右移,偏移量減少,錨點(diǎn)定位的視圖左移。
對(duì)于NSLayoutYAxisAnchor對(duì)象,當(dāng)使用topAnchor(頂部)或bottomAnchor(底部)時(shí),偏移量增加,錨點(diǎn)定位的視圖下移,偏移量減少,錨點(diǎn)定位的視圖上移。
對(duì)于NSLayoutDimension對(duì)象,偏移量增加,錨點(diǎn)定位的視圖增大,偏移量減少,錨點(diǎn)定位的視圖減小。
NSLayoutXAxisAnchor - X軸布局錨
繼承自NSLayoutAnchor,NSLayoutXAxisAnchor會(huì)將類型信息添加到繼承自NSLayoutAnchor的方法中。具體來說,NSLayoutAnchor聲明的泛型方法現(xiàn)在必須接受一個(gè)匹配的NSLayoutXAxisAnchor對(duì)象,這在一定程度上防止創(chuàng)建無效的約束。
例如 :
// 此約束有效
[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
// 這個(gè)約束產(chǎn)生一個(gè)不兼容的指針類型警告
[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.topAnchor constant: 8.0].active = true;
NSLayoutXAxisAnchor的常用函數(shù)
- (NSLayoutDimension *)anchorWithOffsetToAnchor:(NSLayoutYAxisAnchor *)otherAnchor API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0));
函數(shù)描述 :從兩個(gè)錨點(diǎn)創(chuàng)建布局尺寸對(duì)象。使用返回的對(duì)象來定義當(dāng)前錨點(diǎn)相對(duì)于和 otherAnchor 參數(shù)中的錨點(diǎn)對(duì)象之間的空間的約束。
參數(shù) :
otherAnchor : 創(chuàng)建布局尺寸時(shí)要使用的相對(duì)錨點(diǎn)。
返回值 : 由兩個(gè)錨表示的NSLayoutDimension對(duì)象。
NSLayoutYAxisAnchor - Y軸布局錨
繼承自NSLayoutAnchor,NSLayoutYAxisAnchor將類型信息添加到繼承自NSLayoutAnchor的方法中。具體來說,NSLayoutAnchor聲明的泛型方法現(xiàn)在必須接受一個(gè)匹配的NSLayoutYAxisAnchor對(duì)象,這在一定程度上防止創(chuàng)建無效的約束。
例如 :
// 此約束有效
[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
// 這個(gè)約束產(chǎn)生一個(gè)不兼容的指針類型警告
[self.cancelButton.topAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
NSLayoutYAxisAnchor的常用函數(shù)
- (NSLayoutDimension *)anchorWithOffsetToAnchor:(NSLayoutYAxisAnchor *)otherAnchor API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0));
函數(shù)描述 :從兩個(gè)錨點(diǎn)創(chuàng)建布局尺寸對(duì)象。使用返回的對(duì)象來定義當(dāng)前錨點(diǎn)相對(duì)于和 otherAnchor 參數(shù)中的錨點(diǎn)對(duì)象之間的空間的約束。
參數(shù) :
otherAnchor : 創(chuàng)建布局尺寸時(shí)要使用的相對(duì)錨點(diǎn)。
返回值 : 由兩個(gè)錨表示的NSLayoutDimension對(duì)象。
NSLayoutDimension - 布局尺寸
繼承自NSLayoutAnchor,除了為創(chuàng)建約束提供特定大小的方法外,這個(gè)類還將類型信息添加到繼承自NSLayoutAnchor的方法中。具體來說,由NSLayoutAnchor聲明的泛型方法現(xiàn)在必須接受一個(gè)匹配的NSLayoutDimension對(duì)象,這在一定程度上防止創(chuàng)建無效的約束。
例如 :
// 此約束有效
[self.saveButton.widthAnchor constraintEqualToAnchor:self.cancelButton.widthAnchor].active = YES;
// 這個(gè)約束產(chǎn)生一個(gè)不兼容的指針類型警告
[self.saveButton.widthAnchor constraintEqualToAnchor:self.cancelButton.leadingAnchor].active = YES;
NSLayoutDimension的常用函數(shù)
- (NSLayoutConstraint *)constraintEqualToConstant:(CGFloat)c __attribute__((warn_unused_result));
函數(shù)描述 :返回一條約束,該約束為錨定視圖的size屬性中寬或高定義為常量大小。這取決于視圖錨的類型。
參數(shù) :
c :一個(gè)常量,表示與此錨定視圖size屬性某一維度(寬或高)的關(guān)聯(lián)的屬性的大小。
返回值 :一個(gè)NSLayoutConstraint對(duì)象,它為與這個(gè)錨定視圖size屬性某一維度(寬或高)定義一個(gè)常量大小。
UIView (UIViewLayoutConstraintCreation) - 創(chuàng)建視圖布局約束
擴(kuò)展于UIView中的屬性為我們提供了創(chuàng)建約束的便利錨點(diǎn),如下 :
//表示視圖框架前緣的布局定位
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *leadingAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架后緣的布局定位
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *trailingAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架左側(cè)的布局定位
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *leftAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架右側(cè)的布局定位
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *rightAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架頂部的布局定位
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *topAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架底部的布局定位
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *bottomAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架寬
@property(nonatomic,readonly,strong) NSLayoutDimension *widthAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架高
@property(nonatomic,readonly,strong) NSLayoutDimension *heightAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架X軸中心點(diǎn)
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *centerXAnchor API_AVAILABLE(ios(9.0));
//表示視圖框架Y軸中心點(diǎn)
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *centerYAnchor API_AVAILABLE(ios(9.0));
//表示視圖中最頂行文本的基線
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *firstBaselineAnchor API_AVAILABLE(ios(9.0));
//表示視圖中文本最底行的基線。
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *lastBaselineAnchor API_AVAILABLE(ios(9.0));
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view2 = [[UIView alloc]initWithFrame:CGRectZero];
view2.backgroundColor = [UIColor greenColor];
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view2];
[view2.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[view2.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[view2.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
[view2.heightAnchor constraintEqualToConstant:200].active = YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view2 = [[UIView alloc]initWithFrame:CGRectZero];
view2.backgroundColor = [UIColor greenColor];
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view2];
[NSLayoutConstraint activateConstraints:@[
[view2.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[view2.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[view2.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[view2.heightAnchor constraintEqualToConstant:200],
]];
}
豎屏?xí)r效果如下 :
橫屏?xí)r效果如下 :
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view1 = [[UIView alloc]initWithFrame:CGRectZero];
view1.backgroundColor = [UIColor blueColor];
view1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view1];
[NSLayoutConstraint activateConstraints:@[
[view1.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[view1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[view1.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[view1.heightAnchor constraintEqualToConstant:200],
]];
__block UIView *view2 = [[UIView alloc]initWithFrame:CGRectZero];
view2.backgroundColor = [UIColor greenColor];
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view2];
[NSLayoutConstraint activateConstraints:@[
[view2.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[view2.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[view2.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[view2.heightAnchor constraintEqualToConstant:200],
]];
//獲取self.view上添加的約束
NSArray<__kindof NSLayoutConstraint *> *constraints = view2.superview.constraints;
//遍歷self.view上添加的約束
[constraints enumerateObjectsUsingBlock:^(__kindof NSLayoutConstraint * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//根據(jù)約束對(duì)象找到view2
if ([obj.firstItem isEqual:view2]) {
//找到view2的頂部約束
if (obj.firstAttribute == NSLayoutAttributeTop) {
//修改constant常量
obj.constant = 50;
}
//獲取view2對(duì)象
view2 = obj.firstItem;
//獲取view2上添加的約束
NSArray<__kindof NSLayoutConstraint *> *view2constraints = view2.constraints;
//遍歷view2上添加的約束
[view2constraints enumerateObjectsUsingBlock:^(__kindof NSLayoutConstraint * _Nonnull view2obj, NSUInteger idx, BOOL * _Nonnull stop) {
///找到view2的高度約束
if (view2obj.firstAttribute == NSLayoutAttributeHeight) {
//修改constant常量
view2obj.constant = 100;
}
}];
}
}];
}
修改約束常數(shù)后效果如圖 :
UIView (UIConstraintBasedLayoutInstallingConstraints) -- 基于約束的布局安裝約束
擴(kuò)展自UIView,用于添加約束,約束通常安裝在視圖約束中涉及的最近的父視圖上。約束中的數(shù)字將在安裝該約束的視圖的坐標(biāo)系中進(jìn)行解釋。
UIView (UIConstraintBasedLayoutInstallingConstraints)的常用屬性
@property(nonatomic,readonly) NSArray<__kindof NSLayoutConstraint *> *constraints API_AVAILABLE(ios(6.0));
屬性描述 : 視圖所包含的約束。
UIView (UIConstraintBasedLayoutInstallingConstraints)的常用函數(shù)
//為視圖添加約束,在為iOS 8.0或更高版本開發(fā)時(shí),采用將約束的active屬性設(shè)置為YES。
- (void)addConstraint:(NSLayoutConstraint *)constraint API_AVAILABLE(ios(6.0));
//為視圖添加一組約束,在為iOS 8.0或更高版本開發(fā)時(shí),請(qǐng)使用NSLayoutConstraint類的activateConstraints:方法。
- (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints API_AVAILABLE(ios(6.0));
//為視圖移除指定的約束,在為iOS 8.0或更高版本開發(fā)時(shí),采用將約束的active屬性設(shè)置為NO。
- (void)removeConstraint:(NSLayoutConstraint *)constraint API_AVAILABLE(ios(6.0));
//為視圖移除指定的一組約束,在為iOS 8.0或更高版本開發(fā)時(shí),請(qǐng)使用NSLayoutConstraint類的deactivateConstraints:方法。
- (void)removeConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints API_AVAILABLE(ios(6.0));
UILayoutGuide - 布局占位
UILayoutGuide會(huì)創(chuàng)建一個(gè)用于占位的對(duì)象,它可以表示為一個(gè)矩形,并與自動(dòng)布局交互,它不會(huì)顯示在視圖層次結(jié)構(gòu)中,可以用來包含和封裝部分用戶界面,使復(fù)雜的頁面模塊化,簡化自動(dòng)布局約束邏輯。對(duì)比使用其它會(huì)顯示在視圖層次結(jié)構(gòu)中的對(duì)象作為占位圖,UILayoutGuide創(chuàng)建和維護(hù)成本更低,也更安全。使用init方法創(chuàng)建一個(gè)UILayoutGuide,然后用[UIView addLayoutGuide:]添加之后設(shè)置約束。
- (void)viewDidLoad {
[super viewDidLoad];
UILayoutGuide *packGuide = [[UILayoutGuide alloc]init];
[self.view addLayoutGuide:packGuide];
[NSLayoutConstraint activateConstraints:@[
[packGuide.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
[packGuide.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
[packGuide.widthAnchor constraintEqualToConstant:300],
[packGuide.heightAnchor constraintEqualToConstant:300],
]];
UIView *redView = [[UIView alloc]initWithFrame:CGRectZero];
redView.backgroundColor = [UIColor redColor];
redView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:redView];
[NSLayoutConstraint activateConstraints:@[
[redView.topAnchor constraintEqualToAnchor:packGuide.topAnchor],
[redView.leadingAnchor constraintEqualToAnchor:packGuide.leadingAnchor],
[redView.widthAnchor constraintEqualToConstant:150],
[redView.heightAnchor constraintEqualToConstant:150],
]];
UIView *greenView = [[UIView alloc]initWithFrame:CGRectZero];
greenView.backgroundColor = [UIColor greenColor];
greenView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:greenView];
[NSLayoutConstraint activateConstraints:@[
[greenView.topAnchor constraintEqualToAnchor:packGuide.topAnchor],
[greenView.trailingAnchor constraintEqualToAnchor:packGuide.trailingAnchor],
[greenView.widthAnchor constraintEqualToConstant:150],
[greenView.heightAnchor constraintEqualToConstant:150],
]];
UIView *yellowView = [[UIView alloc]initWithFrame:CGRectZero];
yellowView.backgroundColor = [UIColor yellowColor];
yellowView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:yellowView];
[NSLayoutConstraint activateConstraints:@[
[yellowView.centerXAnchor constraintEqualToAnchor:packGuide.centerXAnchor],
[yellowView.bottomAnchor constraintEqualToAnchor:packGuide.bottomAnchor],
[yellowView.widthAnchor constraintEqualToConstant:150],
[yellowView.heightAnchor constraintEqualToConstant:150],
]];
}
UILayoutGuide放置在視圖上,但是是不顯示在圖層結(jié)構(gòu)中的:
UILayoutGuide同樣提供了布局使用的錨點(diǎn)屬性:
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *leadingAnchor;
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *trailingAnchor;
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *leftAnchor;
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *rightAnchor;
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *topAnchor;
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *bottomAnchor;
@property(nonatomic,readonly,strong) NSLayoutDimension *widthAnchor;
@property(nonatomic,readonly,strong) NSLayoutDimension *heightAnchor;
@property(nonatomic,readonly,strong) NSLayoutXAxisAnchor *centerXAnchor;
@property(nonatomic,readonly,strong) NSLayoutYAxisAnchor *centerYAnchor;
SizeClasses(屏幕適配)
在Interface Builder(故事板)中使用,通過結(jié)合Auto Layout技術(shù),使設(shè)置的約束可以適應(yīng)不同設(shè)備的屏幕大小。蘋果將不同的設(shè)備在不同的狀態(tài)下,根據(jù)屏幕的寬高進(jìn)行了分類,屏幕的寬高分為Compact(緊湊)、Regular(常規(guī))類型與Any(任意)類型,然后可以根據(jù)屏幕寬高的分類,對(duì)視圖進(jìn)行約束,我們通過iPhone11為一個(gè)App設(shè)置啟動(dòng)圖觀察一下:
首先在LaunchScreen.storyboard中在設(shè)備豎屏的情況下,設(shè)置啟動(dòng)圖,如圖:
但當(dāng)屏幕橫屏?xí)r,啟動(dòng)圖就產(chǎn)生了問題,這顯然不是我們需要的,如圖:
我們先去觀察一下豎屏?xí)r,Xcode的設(shè)置面板:
我們將豎屏狀態(tài)下的約束進(jìn)行逐條的安裝,安裝操作如下:
之后我們將設(shè)置狀態(tài)改為橫屏,并取消默認(rèn)的約束安裝,此時(shí)視圖約束開始報(bào)錯(cuò),因?yàn)闄M屏狀態(tài)下,控件的約束還都未設(shè)置,需要我們重新添加。操作如下:
重新設(shè)置橫屏狀態(tài)下的約束后,橫屏?xí)r,啟動(dòng)圖展示如下 :
設(shè)置的約束一定要區(qū)分狀態(tài)進(jìn)行安裝,否則頁面容易錯(cuò)亂,然后我們對(duì)比一下不同狀態(tài)時(shí),安裝約束給出的默認(rèn)值:
豎屏?xí)r :
橫屏?xí)r:
我們可以對(duì)比出在iPhone11下,豎屏?xí)r,屏幕寬度是Compact(緊湊)的,高度是Regular(常規(guī))的,但設(shè)備橫屏?xí)r,寬度是Regular(常規(guī))的,高度是Compact(緊湊)的,根據(jù)這種分類,我們?cè)O(shè)置了視圖不同的約束。但是這些分類在不同的設(shè)備中是不一樣的,在iPhoneSE下,豎屏?xí)r,屏幕寬度是Compact(緊湊)的,高度是Regular(常規(guī))的,但設(shè)備橫屏?xí)r,屏幕寬度與高度是Compact(緊湊)的,而在ipad中,豎屏與橫屏?xí)r,寬度與高度都是Regular(常規(guī))的。這需要多種不同的約束讓視圖以不同的狀態(tài)適應(yīng)屏幕。
圖片資源也是有這些分類的,我們可以根據(jù)分類的不同設(shè)置不同的圖片,如圖:
豎屏?xí)r:
橫屏?xí)r:
添加約束的注意事項(xiàng)
1.如果視圖的布局方式為autolayout,再添加約束之前要將視圖的translatesAutoresizingMaskIntoConstraints屬性設(shè)為NO,否則會(huì)約束沖突。
2.確保將子視圖添加到父視圖后再添加約束,如果子視圖未添加到父視圖就添加約束么,會(huì)拋出NSInternalInconsistencyException異常,提示原因?yàn)闊o法設(shè)置視圖層次結(jié)構(gòu)未準(zhǔn)備好約束的布局。
添加約束選擇目標(biāo)View的規(guī)則
- 對(duì)于兩個(gè)同層級(jí)View之間的約束關(guān)系,添加到他們的父View上。
- 對(duì)于兩個(gè)不同層級(jí)View之間的約束關(guān)系,添加到他們最近的共同的父View上
- 對(duì)于有層次關(guān)系的兩個(gè)View之間的約束關(guān)系,添加到層次較高的父View上
至此,系統(tǒng)提供的糟糕的約束方法我們可以簡單的使用了,然后我們愉快的去使用Masonry,有封裝好的約束布局庫,和系統(tǒng)方法較什么勁呢??。