![iOS自動佈局(Autolayout)之VFL(視覺化格式語言)](https://i.iter01.com/images/bf6468364e1e233b9d514fd19c48d4ac0465b2d5f59a7645a024aba4cb0d9f66.png)
作為一個移動端的程式設計師,佈局永遠都是需要打交道的東西,最初剛入門那會,用的storyboard,xib手動拖拽的方式設定約束,看起來是直觀了,但是費時又費力還吃力不討好,感覺還是沒有純純的程式碼好用。
程式碼約束最初還是靠本人機密的計算,算比例算數值各種算,約束是沒問題了,時間浪費了很多,計算能力倒是增強了不少 T-T。。。。。。。。
後來我發現了個好東西
UIView *v1 = [[UIView alloc] initWithFrame:CGRectZero];
v1.translatesAutoresizingMaskIntoConstraints = NO;
v1.backgroundColor = [UIColor redColor];
[self.view addSubview:v1];
UIView *v2 = [[UIView alloc] initWithFrame:CGRectZero];
v2.backgroundColor = [UIColor grayColor];
v2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:v2];//新增兩個允許自動佈局的子檢視
[self.viewaddConstraint:[NSLayoutConstraint constraintWithItem:v1attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.viewattribute:NSLayoutAttributeHeight multiplier:0.5constant:0]];//設定子檢視的高度是父檢視高度的一半
大致就是這樣一種約束形式,是不是覺得很長,而且沒有註釋的話一眼還看不出來是哪哪的約束,於是我又找了找,發現了這個
VFL
Visual Format Language,簡稱VFL 即“視覺化格式語言”。
VFL是一種宣告性語言,VFL允許您通過一個格式化後的程式碼字串迅速定義檢視的自動佈局約束
他給人的感覺就是直觀,因為你會發現很多的這個
H:|-20-[view1]-30-[view2(==view1)]-20-|
看到這個是不是蒙圈了,不要急,其實這東西還是蠻簡單的,慢慢看看規則一學就會了,接下來我就快速的解釋一下
首先
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary*)metrics views:(NSDictionary*)views;
運用這個api就能簡單實現約束了,當然VFL還是要寫的
format 格式規範的約束。
opts 描述VFL中的所有物件的屬性和佈局的方向 。
metrics 一個字典,字典的key必須是在VFL字串中被使用的字串,值必須是NSNumber物件
views 出現在在VFL字串中的檢視組成的字典, 字典的key必須是在VFL字串中被使用的字串。並且其值必須是一個View物件
先來一段程式碼
_view1= [[UIViewalloc]init];
_view1.backgroundColor= [UIColorwhiteColor];
_view1.translatesAutoresizingMaskIntoConstraints=NO;
_view2= [[UIViewalloc]init];
_view2.backgroundColor= [UIColorgreenColor];
_view2.translatesAutoresizingMaskIntoConstraints=NO;
UIView*view4 = [[UIViewalloc]init];
view4.backgroundColor= [UIColorpurpleColor];
view4.translatesAutoresizingMaskIntoConstraints=NO;
[self.viewaddSubview:_view1];
[self.viewaddSubview:_view2];
self.view.backgroundColor= [UIColorgrayColor];
UIView*view1 =_view1;
UIView*view2 =_view2;
NSDictionary*bindings =NSDictionaryOfVariableBindings(view1,view2);
NSArray*constraints=[NSLayoutConstraintconstraintsWithVisualFormat:@"H:|-20-[view1]-30-[view2(==view1)]-20-|"options:0metrics:nilviews:bindings];
NSArray*constraints2=[NSLayoutConstraintconstraintsWithVisualFormat:@"V:|-20-[view1(40)]"options:0metrics:nilviews:NSDictionaryOfVariableBindings(view1)];
NSArray*constraints3=[NSLayoutConstraintconstraintsWithVisualFormat:@"V:|-20-[view2(40)]"options:0metrics:nilviews:NSDictionaryOfVariableBindings(view2)];
[self.viewaddConstraints:constraints];
[self.viewaddConstraints:constraints2];
[self.viewaddConstraints:constraints3];
效果是這樣的
![iOS自動佈局(Autolayout)之VFL(視覺化格式語言)](https://i.iter01.com/images/9b0f30b6da5734819251fad741e6b8d91facedde5f173f420269956b70c46c12.gif)
螢幕怎麼轉我的控制元件在我的控制之中這就是VFL的方便之處,哈哈、。
解釋開始:
VFL 語法
(<方向>:)?(<父檢視前><連線>)?[<被佈局檢視>]!(<連線><其他檢視>)*(<連線><父檢視後>)?
1 2 3 4 5
?問號指的是一個可選項,不是必需的。*指的是該項會出現0次或者多次。!代表必需指定
雖然該定義看上去令人生畏,但是事實上這些字串相當容易構建。
例如:
“H:|-[view1]-[view2]-(>=8)-[view3]-|”
VFL格式字串:
1.方向:約束在座標軸上的方向。H代表水平方向排列,V代表垂直方向排列,不指定代表預設值水平方向
2.父檢視前:關聯到父檢視前邊緣。 垂直方向上的被佈局檢視頂部邊緣與父檢視頂部邊緣的距離,水平方向上的被佈局檢視前邊緣與父檢視前邊緣的距離
3.被佈局檢視:你新增layout的檢視。
4.其他檢視:被佈局檢視關聯的另外一個檢視
5.父檢視後:關聯到父檢視後邊緣。垂直方向上的被佈局檢視底部邊緣與父檢視底部邊緣的距離,水平方向上的被佈局檢視後邊緣與父檢視後邊緣的距離
檢視名稱
檢視的名稱被一對方括號包圍,例如你可以使用[thisView],[thatView]。當使用變數繫結字典時,檢視的名稱指的是本地變數名。
父檢視
總是用一個特殊的字元 豎線“|”,來表示父檢視,僅會在VFL的開頭或者結尾出現。在開頭時候,它恰好出現在水平或者垂直方向指定符之後(“V:|”或者“H:|”)。在結尾時,它恰好出現在引號之前(“.....|”)。
無需在繫結字典中命名父檢視。AutoLayout知道“|”代表父檢視。
使用父檢視的典型包括:
延伸一個檢視來適應它的父檢視,例如“H:|[view]|”
將一個檢視偏離它的父檢視的某條變,例如“V:[view]-8-”
建立一列或一行與父檢視對齊的檢視,例如“V:[view1]-[view2]-[view3]-[view4]”
連線
連線指定檢視直接的間隔。每個檢視(包括父檢視的引用)間的連線標明瞭要新增的間距。
空連線
空連線看起來像“ H:[view1][view2]”,在每個檢視的方括號直接沒有任何符號,沒有指定任何東西,顯示效果將是兩個檢視僅僅的貼在了一起
標準間隔
連線符 - 代表一個標準的固定間隔,比如“ H:[view1]-[view2]”,每個檢視直接增加了一個小的間隙,儘管官方並沒有文件化,但標準間隔一般對於檢視到檢視佈局為8點,對於檢視到父檢視為20點。標準間隔確保相關聯但是又完全分離的檢視以足夠的視覺間隔顯示。
數字間隔
可以在兩個方括號直接使用一對連字元中間夾著數字來設定準確的間隔大小,約束“ H:[view1]-30-[view2]”在兩個檢視之間增加了一個30點的間隔。
引用父檢視
格式“ H:|[view1]-[view2]|”確定了以父檢視開頭的水平佈局。父檢視後緊跟的是第一個檢視,然後是一個間隔和第二個檢視,之後是一個豎線符也就是是父檢視。
與父檢視的間隔
格式“ H:|-[view1]-[view2]-|”為前後邊緣到父檢視,每個增加了一個標準間隔 20點
格式“ H:|[view1]-[view2]-50-|”為後邊緣到父檢視,增加了一個自定義間隔 50點
靈活間隔
如果是目標是在檢視間新增一個靈活間隔,同也有辦法。為兩個檢視新增一個關係規則(例如“H:|-[view1]-(>=0)-[view2]-|”),允許這兩個檢視保持他們的尺寸,在維護他們的邊緣同父檢視的間隔時將他們分離出來。
這個規則可以讀作“至少0點間距”,提供了使檢視分開的更靈活的方式。
當說“至少50點”(>50 )或者“不超過30帶你”(<=30)時,不能將間距和標準間隔結合起來是有。例如>=-,<=1是非法的。你只能使用等值數值。記住,標準的檢視到時間間隔是8點,而檢視到父檢視的間隔是20帶你。
圓括號
為了清晰可見,關係(>=0)被放在一堆括號中,括號將非常簡單的正數或者負數或者度量名間隔區分開來
在如何表達規則時,你可以對視覺化約束有很大的靈活性。如下規則都實現兩個相互眥鄰的檢視:
[view1][view2]
[view1]-0-[view2]
[view1]-(0)-[view2]
[view1]-(==0)-[view2]
[view1]-(>=0,<=0)-[view2]
[view1]-(==0@1000)-[view2]
[view1]-(>=0,<=0,<=30)-[view2]
當在括號中新增多個關係時,使用逗號分隔各項。符號@表示一個優先順序
負數
比如為任何使用負數值的間隔加上括號。如下約束是非法的:
V:[view1]--5-[view2]
負數在視覺化約束中是允許的,正確寫法
V:[view1]-(-5)-[view2]
優先順序
在任何連線或者尺寸規則後拼接一個@符號,@符號後是一個想要設定的優先順序。為了清晰可見,最好將其使用圓括號括起來
例如:
“H:|-(5@20)[view1]-[view2]-|”
間隔規則優先順序預設是必須的(值為1000),因為將優先順序降到了20,所以兩個檢視改變尺寸的方式可以能會影響佈局。
多檢視
格式檢視並不侷限於一個或者兩個檢視,我可以很容易的插入第三個,第四個或者更多。
“H:|-[view1]-[view2]-(>=8)-[view3]-|”
檢視尺寸
VFL除了可以用方括號分隔檢視名稱外,還可以在方括號中指定檢視的尺寸。可以在名稱之後的圓括號裡指定值,例如:
可以指定一個檢視的寬度為120點固定值:“H:[view1(120)]”。如果你喜歡顯示的說明關係,也可以新增這樣的格式“H:[view1(==120)]”
可以指定一個檢視的寬度至少50點,使用如下約束:“H:[view1(>=50)]”,50-70點之間“H:[view1(>=50,<=70)]”
可以引用其他檢視指定尺寸:”H:|[view1(view2)-[view2]-|]“,因為約束是無方向的,所以可以自我引用,可以使用如下方式建立一個相等佈局:”H:|[view1(view2)-[view2(view2)]-|]“,迴圈定義不會產生效能損失。
不是所有檢視都需要參與尺寸匹配。一個請求可以圍繞一個基本檢視建立側翼檢視
檢視尺寸也可以表示優先順序。在格式化字串“H:|[view1(==250@700)]-[view2(==250@701)]-|”中,view1和view2都請求寬度為250點,view2獲勝,因為他的請求有更大的優先順序,所以首先拉伸view2
儘管可以很容易地在程式碼中使用乘數來建立表達相對尺寸的約束,但是無法在視覺化約束中那樣做。這是一個非法約束::”H:|[view1==2*view2]-[view2]-|“。如果想說“view1寬度是view2的兩倍”,就需要在程式碼中實現
看的好暈,好吧其實我也做了個小demo,順便放了很多其它東西,如果覺得有用可以自己下載
VFLDemo:github.com/taosiyu/TSY…
可以的話給個star