iOS開發(fā)之 Autolayout 詳解
1. 概述
- Autolayout 是 Apple 自 iOS6 開始引入的旨在解決不同屏幕之間布局適配的技術(shù)
- 蘋果官方推薦開發(fā)者使用 Autolayout 進(jìn)行UI界面的布局
- Autolayout 有兩個(gè)核心概念:1. 參照揣炕。 2. 約束
- 使用Autolayout的注意點(diǎn):
- 添加約束之前需要保證控件已被添加到父控件中
- 不需要再給View設(shè)置frame
- 禁止 autoresizing 功能唱较。
2. 代碼實(shí)現(xiàn) Autolayout
2.1 步驟:
把 View 添加到父控件上含潘。
-
添加約束到相應(yīng)的 View 上反璃。
- (void)addConstraint:(NSLayoutConstraint *)constraint; - (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints;
自動(dòng)布局核心公式:
obj1.property1 =(obj2.property2 * multiplier)+ constant value
NSLayoutConstraint
/**
view1 :要約束的控件
attr1 :約束的類型(做怎樣的約束)
relation :與參照控件之間的關(guān)系
view2 :參照的控件
attr2 :約束的類型(做怎樣的約束)
multiplier :乘數(shù)
c :常量
*/
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
2.2 實(shí)例
添加一個(gè)左間距100 上間距200丧失,寬150 高64 的紅視圖:
- (void)testAutolayout1 {
UIView *redV = [[UIView alloc] init];
redV.backgroundColor = [UIColor redColor];
redV.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:redV];
/**
view1 :要約束的控件
attr1 :約束的類型(做怎樣的約束)
relation :與參照控件之間的關(guān)系
view2 :參照的控件
attr2 :約束的類型(做怎樣的約束)
multiplier :乘數(shù)
c :常量
*/
/// 左間距100:
NSLayoutConstraint *consLeft = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:100];
[self.view addConstraint:consLeft];
/// 上間距200:
NSLayoutConstraint *consTop = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:200];
[self.view addConstraint:consTop];
/// 寬150:
NSLayoutConstraint *consWidth = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1.0 constant:150];
[redV addConstraint:consWidth];
/// 高64:
NSLayoutConstraint *consHeight = [NSLayoutConstraint constraintWithItem:redV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1.0 constant:64];
[redV addConstraint:consHeight];
}
在上視圖基礎(chǔ)上添加一個(gè)與紅視圖右間距相同恕汇,高度相同阀坏,頂部距離紅色視圖間距20肤视,寬度為紅色視圖一半的藍(lán)色View
UIView *blueV = [[UIView alloc] init];
blueV.backgroundColor = [UIColor blueColor];
blueV.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:blueV];
/// 和 redV 右間距為0
NSLayoutConstraint *b_consRight = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0];
[self.view addConstraint:b_consRight];
/// 和 redV 等高
NSLayoutConstraint *b_consHeight = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0];
[self.view addConstraint:b_consHeight];
/// 寬度是 redV 的一半
NSLayoutConstraint *b_consWidth = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0.0];
[self.view addConstraint:b_consWidth];
/// 頂部距離 redV 20
NSLayoutConstraint *b_consTop = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20.0];
[self.view addConstraint:b_consTop];
最終效果:
2.3 添加約束的規(guī)則
在創(chuàng)建約束之后橄教,需要將其添加到作用的view上橙依。
在添加時(shí)要注意目標(biāo)view需要遵循以下規(guī)則:
(1)對(duì)于兩個(gè)同層級(jí)view之間的約束關(guān)系,添加到它們的父view上
(2)對(duì)于兩個(gè)不同層級(jí)view之間的約束關(guān)系拴曲,添加到他們最近的共同父view上
(3)對(duì)于有層次關(guān)系的兩個(gè)view之間的約束關(guān)系,添加到層次較高的父view上
3. VFL
VFL全稱是Visual Format Language凛忿,翻譯過來是“可視化格式語言”澈灼,是蘋果公司為了簡化Autolayout的編碼而推出的抽象語言。
/*
format :VFL語句
opts :約束類型
metrics :VFL語句中用到的具體數(shù)值
views :VFL語句中用到的控件
*/
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *,id> *)views;
@{@"redV" : redV}
等價(jià)于 NSDictionaryOfVariableBindings(redV)
NSDictionary *views =
NSDictionaryOfVariableBindings(blueView, redView);
NSArray *conts2 =
[NSLayoutConstraint constraintsWithVisualFormat:
@"V:[blueView(==blueHeight)]-margin-|" options:0 metrics:
@{@"blueHeight" : @40, @"margin" : @20} views:views];
約束格式說明:
水平方向 H:
垂直方向 V:
Views [view]
SuperView |
關(guān)系 >=,==,<=
空間,間隙 -
優(yōu)先級(jí) @value
3.1 VFL 部分語法:
H:|-100-[redV(200)]-|
水平方向距離左邊距100店溢,寬度200
V:|-200-[redV(64)]-|
垂直方向距離頂部200叁熔,高度64
H:[redV(72)]-12-[blueV(50)]
水平方向redV 寬度72,blueV 寬度50床牧,他們之間間距12
H:[redV(>=60@700)]
水平方向redV寬度大于等于60荣回,優(yōu)先級(jí)為700 (優(yōu)先級(jí)最大1000)
V:[redBox]-[yellowBox(==redBox)]
豎直方向上,先有一個(gè)redBox叠赦,其下方緊接一個(gè)高度等于redBox高度的yellowBox
H:|-10-[Find]-[FindNext]-[FindField(>=20)]-|
水平方向上驹马,F(xiàn)ind距離父view左邊緣默認(rèn)間隔寬度,之后是FindNext距離Find間隔默認(rèn)寬度除秀;再之后是寬度不小于20的FindField糯累,它和FindNext以及父view右邊緣的間距都是默認(rèn)寬度。(豎線“|” 表示superview的邊緣)
3.2 VFL的語法
- 標(biāo)準(zhǔn)間隔:[button]-[textField]
- 寬約束:[button(>=50)]
- 與父視圖的關(guān)系:|-50-[purpleBox]-50-|
- 垂直布局:V:[topField]-10-[bottomField]
- Flush Views:[maroonView][buleView]
- 權(quán)重:[button(100@20)]
- 等寬:[button(==button2)]
- Multiple Predicates:[flexibleButton(>=70,<=100)]
注意事項(xiàng)
創(chuàng)建這種字符串時(shí)需要注意一下幾點(diǎn):
- H:和V:每次都使用一個(gè)册踩。
- 視圖變量名出現(xiàn)在方括號(hào)中泳姐,例如[view]。
- 字符串中順序是按照從頂?shù)降自菁瑥淖蟮接?/li>
- 視圖間隔以數(shù)字常量出現(xiàn)胖秒,例如-10-。
- |表示父視圖
3.3 使用Auto Layout時(shí)需要注意的點(diǎn)
- 注意禁用Autoresizing Masks慕的。對(duì)于每個(gè)需要使用Auto Layout的視圖需要調(diào)用setTranslatesAutoresizingMaskIntoConstraints:NO
- VFL語句里不能包含空格和>阎肝,<這樣的約束
- 布局原理是由外向里布局,最先屏幕尺寸肮街,再一層一層往里決定各個(gè)元素大小风题。
- 刪除視圖時(shí)直接使用removeConstraint和removeConstraints時(shí)需要注意這樣刪除是沒法刪除視圖不支持的約束導(dǎo)致view中還包含著那個(gè)約束(使用第三方庫時(shí)需要特別注意下)。解決這個(gè)的辦法就是添加約束時(shí)用一個(gè)局部變量保存下,刪除時(shí)進(jìn)行比較刪掉和先前那個(gè)沛硅,還有個(gè)辦法就是設(shè)置標(biāo)記眼刃,constraint.identifier = @“What you want to call”。
3.4 布局約束規(guī)則
表達(dá)布局約束的規(guī)則可以使用一些簡單的數(shù)學(xué)術(shù)語摇肌,如下表
類型 | 描述 | 值 |
---|---|---|
屬性 | 視圖位置 | NSLayoutAttributeLeft, NSLayoutAttributeRight, NSLayoutAttributeTop, NSLayoutAttributeBottom |
屬性 | 視圖前面后面 | NSLayoutAttributeLeading, NSLayoutAttributeTrailing |
屬性 | 視圖的寬度和高度 | NSLayoutAttributeWidth, NSLayoutAttributeHeight |
屬性 | 視圖中心 | NSLayoutAttributeCenterX, NSLayoutAttributeCenterY |
屬性 | 視圖的基線擂红,在視圖底部上方放置文字的地方 | NSLayoutAttributeBaseline |
屬性 | 占位符,在與另一個(gè)約束的關(guān)系中沒有用到某個(gè)屬性時(shí)可以使用占位符 | NSLayoutAttributeNotAnAttribute |
關(guān)系 | 允許將屬性通過等式和不等式相互關(guān)聯(lián) | NSLayoutRelationLessThanOrEqual, NSLayoutRelationEqual, NSLayoutRelationGreaterThanOrEqual |
數(shù)學(xué)運(yùn)算 | 每個(gè)約束的乘數(shù)和相加性常數(shù) | CGFloat值 |
3.5 View的改變會(huì)調(diào)用哪些方法
- 改變frame.origin不會(huì)掉用layoutSubviews
- 改變frame.size會(huì)使 superVIew的layoutSubviews調(diào)用和自己view的layoutSubviews方法
- 改變bounds.origin和bounds.size都會(huì)調(diào)用superView和自己view的layoutSubviews方法
3.6 VFL 實(shí)例:
- (void)testVFL {
UIView *redV = [[UIView alloc] init];
redV.backgroundColor = [UIColor redColor];
redV.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:redV];
UIView *blueV = [[UIView alloc] init];
blueV.backgroundColor = [UIColor blueColor];
blueV.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:blueV];
/*
format :VFL語句
opts :約束類型
metrics :VFL語句中用到的具體數(shù)值
views :VFL語句中用到的控件
*/
//水平方向 redV 左右間距為20
NSArray *cons1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[redV]-20-|" options:0 metrics:nil views:@{@"redV":redV}];
[self.view addConstraints:cons1];
//垂直方法redV距離頂部 100, redV 高度為64, blueV頂部距離redV 100 像素, blueV的高度等于redV
NSArray *cons2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-margin-[redV(64)]-margin-[blueV(==redV)]" options:NSLayoutFormatAlignAllRight metrics:@{@"margin" : @100} views:NSDictionaryOfVariableBindings(redV,blueV)];
[self.view addConstraints:cons2];
NSLayoutConstraint *cons = [NSLayoutConstraint constraintWithItem:blueV attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redV attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0.0];
[self.view addConstraint:cons];
}
運(yùn)行結(jié)果: