隨著iPhone6與iOS8的臨近,適配的問題講更加復雜,最近學習了一下Auto Layout的使用,與大家分享。
什麼是Auto Layout?
Auto Layout是iOS6發布後引入的一個全新的布局特性,其目的是彌補以往Autoresizing在布局方面的不足之處,以及未來面對更多尺寸適配時界面布局可以更好的適應。
為什麼要用Auto Layout?
Autolayout能解決不同屏幕(iPhone4,iPhone5,iPad...)之間的適配問題。
在iPhone4時代開發者只需要適配一種屏幕尺寸,相比與Android陣營的相對布局,iOS開發者們最長用的做法是使用絕對布局,坐標和大小只要寫死就ok了。隨後iPhone5出了,對於兩種屏幕尺寸,就需要考慮一個新的問題,屏幕適配。蘋果其實很早就考慮到了這一點Autoresizing技術,誠然Autoresizing有所不足,蘋果在iOS6發布後引入了Autolayout特性,適應更廣泛場景下的布局需求。當然了iPhone5由於和iPhone4在屏幕寬度上一致,即便不用上這些技術適配起來也不麻煩(筆者再之前也只用到了Autoresizing),不過在iPhone6即將推出,即將面臨更復雜的屏幕適配時,Auto Layout能幫助我們很好地解決這個問題,此外也能解決橫屏豎屏切換,iPad的適配問題。
下面是本文事例代碼在橫豎屏切換下的效果:
如何使用Auto Layout?
Auto Layout的基本概念
Auto Layout的核心是約束(constraint),通過對view的約束(view的大小,view與view之間的關系)使得view能夠自己計算出尺寸和坐標。
Visual Format Language,在Auto Layout中使用的形象描述約束的一種語言規則。
Auto Layout的使用還是比較復雜的,一開始用可能會感覺雲裡霧裡的,用的多了習慣VFL的寫法之後就會感覺到它的方便了。
在代碼中使用Auto Layout
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor greenColor]; UIView *viewTopLeft = [[UIView alloc] init]; UIView *viewTopRight = [[UIView alloc] init]; UIView *viewBottom = [[UIView alloc] init]; [viewTopLeft setBackgroundColor:[UIColor blueColor]]; [viewTopRight setBackgroundColor:[UIColor redColor]]; [viewBottom setBackgroundColor:[UIColor blackColor]]; //添加約束之前必須講view添加到superview裡 [self.view addSubview:viewTopRight]; [self.view addSubview:viewTopLeft]; [self.view addSubview:viewBottom]; //對於要使用Auto Layout的控件需要關閉Autoresizing [viewTopLeft setTranslatesAutoresizingMaskIntoConstraints:NO]; [viewTopRight setTranslatesAutoresizingMaskIntoConstraints:NO]; [viewBottom setTranslatesAutoresizingMaskIntoConstraints:NO]; //使用VFL #if 1 //dict和metrics相當於vfl中的名稱與對象和數值的映射 NSDictionary *dict = NSDictionaryOfVariableBindings(viewTopLeft, viewTopRight, viewBottom); //相當於這麼寫 NSDictionary *dict = @[@"viewTopLeft":viewTopLeft, @"viewTopRight":viewTopRight, @"viewBottom",viewBottom];不一定名稱要與對象名一致 NSDictionary *metrics = @{@"pad":@10}; //水平關系(H:,可省略如vfl1),"|"相當與superview,"-"是連接符,表示兩者間的間距也可以沒有表示無間距 //轉化正自然語言的描述就是:superview的左邊界間隔pad距離是viewTopLeft(寬度與viewTopRight相等)再間隔默認距離是viewTopRight再間隔10的距離是superview的右邊界。 NSString *vfl0 = @"H:|-pad-[viewTopLeft(==viewTopRight)]-[viewTopRight]-10-|"; NSString *vfl1 = @"|[viewBottom]|"; //垂直關系(V:) NSString *vfl2 = @"V:|-[viewTopLeft(==viewBottom)]-[viewBottom]-pad-|"; NSString *vfl3 = @"V:|-[viewTopRight]-[viewBottom]-pad-|"; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl0 options:0 metrics:metrics views:dict]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1 options:0 metrics:metrics views:dict]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl2 options:0 metrics:metrics views:dict]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl3 options:0 metrics:metrics views:dict]]; //不使用VFL #else //viewTopLeft的leading與其superview的leading(左側)對齊 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeLeading multiplier:1 constant:-10]]; //viewTopLeft的top與其superview的top對齊 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeTop multiplier:1 constant:-10]]; //viewTopRight的top與viewTopLeft的top對齊 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeTop multiplier:1 constant:0]]; //viewTopRight的leading與viewTopLeft的trailing(右側)對齊 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeTrailing multiplier:1 constant:10]]; //viewTopRight的trailing與其superview的右側對其 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1 constant:-10]]; //viewTopRight的寬與viewTopLeft寬相等 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeWidth multiplier:1 constant:0]]; //viewTopRight的高與viewTopLeft高相等 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopLeft attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:viewTopRight attribute:NSLayoutAttributeHeight multiplier:1 constant:0]]; //viewBottom的top與viewTopRight的bottom對齊 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewTopRight attribute:NSLayoutAttributeBottom multiplier:1 constant:10]]; //viewBottom的bottom與superview的bottom對齊 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:-10]]; //viewBottom的leading與viewTopLeft的leading對齊 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeLeading multiplier:1 constant:0]]; //viewBottom的高與viewTopLeft的高相等 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeHeight multiplier:1 constant:0]]; //viewBottom的寬與其superview的高相等 [self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:-20]]; #endif //更新約束 [self.view setNeedsUpdateConstraints]; [self.view updateConstraintsIfNeeded]; }
注意點:
1.約束必須有給定的size然後通過約束計算出各個view的size和位置,上面self.view的size是給定的,如果superview的size不固定則必須給定某個subview的size才能通過約束計算出其他的。
2.兩個view之間的約束應該放在他們superview上,如果一個view是superview只要放在superview的那個上就行了。
2.約束的設計最好不要沖突,雖然可以設置優先級,但是容易出問題。
3.VFL方式的設置view的size時只有相等,小等或大等3種關系,沒法像使用方法生成約束那樣可以設置兩個view的比例,所以在具體的應用中還是要兩者結合起來使用。
在xib中使用Auto Layout
感覺在xib中使用autolayout還沒有用代碼來的方便,原理與代碼上相同,這裡就不多做描述了。
參考資料
Auto Layout
Guide
ios8來了,屏幕更大,准備好使用 iOS Auto Layout了嗎?
Autolayout及VFL經驗分享