經過對iOS8界面佈局的學習和總結,發現autolayout纔是主角,autolayout是iOS6引入的新特性,當時還粗淺的學習了下,但是沒有真正應用到項目中。隨着iOS設備尺寸逐漸碎片化,純粹的hard code方式UI佈局將會走向死角,而autoresizing方式也有其侷限性,因此不管如何autolayout都將成爲UI佈局的重要方式。html
前兩篇以發燒友心態對iOS8界面佈局的主要元素size class和autolayout進行了探索,發現要徹底掌握autolayout須要大量的時間去實踐總結。因此深刻思考autolayout是頗有必要的。你可能有和我一樣的疑問,以下:git
一、之後一概使用autolayout嗎?除了在storyboard中使用autolayout,代碼方式autolayout如何使用?github
二、好像忽略了一個重要問題,就是view動畫在autolayout如何實現?xcode
三、autolayout有沒有侷限性和解決不了的問題?兼容性怎麼樣?效率怎麼樣?網絡
四、……app
2、研究開始ide
一、直接說之後都應該使用storyboard+autolayout感受是不負責的說法,讀了好多網絡的帖子,最後總結以下狀況使用autolayout會有幫助:佈局
a 當須要展現的內容不少而且尺寸不固定;學習
b 程序需支持屏幕旋轉(主要是iPad程序,iPhone程序橫屏的場景有點非主流);動畫
c 程序通用於iPhone和iPad;
但storyboard中使用autolayout有利有弊,好處固然是可視化,實現簡單功能很節省時間,但也有弊端,例如不當心移動一個控件就會讓弄亂那些約束。拋開storyboard而使用autolayout,就須要代碼定義約束了,並且代碼量也不是很大。當app中一些view的出現時根據網絡數據來決定的時候,代碼方式可能更合適。
先看一個簡單的Demo:
例子1:新建一個Single View Application template項目Demo4,在rootView上添加一個綠顏色的view,使新添加的view四個邊距離superView四邊20點寬
效果如圖:
使用storyboard來實現這個效果很簡單,選中綠色view,而後添加4個相對於superview的邊界約束,約束的數值設置爲20,而後Update Frame就能夠了,由於不區分iOS設備,因此size class能夠設置爲默認的wAny hAny。Demo下載
接下來使用代碼來實現UI佈局,目前有3種方法可使用:(1)最基本的約束實現方式;(2)特殊格式化語言的約束實現方式;(3)第三方UIView-AutoLayout
(1)最基本的約束實現方式
- <span style="font-size:12px;">- (void)viewDidLoad {
- [super viewDidLoad];
-
- self.view.translatesAutoresizingMaskIntoConstraints =NO;
-
- UIView *newView = [UIView new];
- newView.backgroundColor = [UIColor greenColor];
- [self.view addSubview:newView];
-
- newView.translatesAutoresizingMaskIntoConstraints =NO;
-
- NSLayoutConstraint *constraint = nil;
-
- constraint = [NSLayoutConstraint constraintWithItem:newView
- attribute:NSLayoutAttributeLeading
- relatedBy:NSLayoutRelationEqual
- toItem:self.view
- attribute:NSLayoutAttributeLeading
- multiplier:1.0f
- constant:20];
- [self.view addConstraint:constraint];
-
- constraint = [NSLayoutConstraint constraintWithItem:newView
- attribute:NSLayoutAttributeTrailing
- relatedBy:NSLayoutRelationEqual
- toItem:self.view
- attribute:NSLayoutAttributeTrailing
- multiplier:1.0f
- constant:-20];
- [self.view addConstraint:constraint];
-
- constraint = [NSLayoutConstraint constraintWithItem:newView
- attribute:NSLayoutAttributeTop
- relatedBy:NSLayoutRelationEqual
- toItem:self.view
- attribute:NSLayoutAttributeTop
- multiplier:1.0f
- constant:20];
- [self.view addConstraint:constraint];
-
- constraint = [NSLayoutConstraint constraintWithItem:newView
- attribute:NSLayoutAttributeBottom
- relatedBy:NSLayoutRelationEqual
- toItem:self.view
- attribute:NSLayoutAttributeBottom
- multiplier:1.0f
- constant:-20];
- [self.view addConstraint:constraint];
-
- }</span>
(2)特殊格式化語言的約束實現方式
- <span style="font-size:12px;">- (void)viewDidLoad {
- [super viewDidLoad];
- self.view.translatesAutoresizingMaskIntoConstraints =NO;
-
- UIView *newView = [UIView new];
- newView.backgroundColor = [UIColor greenColor];
- [self.view addSubview:newView];
- newView.translatesAutoresizingMaskIntoConstraints =NO;
-
- NSMutableArray *constraintArray = [NSMutableArray array];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[newView]-20-|"
- options:0
- metrics:nil
- views:NSDictionaryOfVariableBindings(newView, self.view)]];
- [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[newView]-20-|"
- options:0
- metrics:nil
- views:NSDictionaryOfVariableBindings(newView, self.view)]];
- [self.view addConstraints:constraintArray];
- }</span>
(3)第三方
UIView-AutoLayout
- <span style="font-size:12px;">- (void)viewDidLoad {
- [super viewDidLoad];
- self.view.translatesAutoresizingMaskIntoConstraints =NO;
-
- UIView *newView = [UIView new];
- newView.backgroundColor = [UIColor greenColor];
- [self.view addSubview:newView];
- newView.translatesAutoresizingMaskIntoConstraints =NO;
-
- [newView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:20.0f];
- [newView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:20.0f];
- [newView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:20.0f];
- [newView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:20.0f];
- }</span>
以上3種方式都實現了咱們想要的效果,看來代碼實現autolayout也不是那麼複雜!
例子2:經過上邊例子咱們實現一個簡單的UI佈局,下面來一個稍微複雜點的,把上一篇中提到3個view佈局的那個例子用代碼佈局實現一下,但難度有所增長,當size class切換的時候,頁面佈局發生相應的改變,效果如圖:
首先初始化3個View:
- <span style="font-size:12px;">- (UIView *) alView {
- UIView *newView = [UIView new];
- newView.translatesAutoresizingMaskIntoConstraints =NO;
-
- return newView;
- }
- UIView *greenView = [self alView];
- greenView.backgroundColor = [UIColor greenColor];
- [self.view addSubview:greenView];
- UIView *yellowView = [self alView];
- yellowView.backgroundColor = [UIColor yellowColor];
- [self.view addSubview:yellowView];
- UIView *blueView = [self alView];
- blueView.backgroundColor = [UIColor blueColor];
- [self.view addSubview:blueView];</span>
接下來適配豎屏的約束:
- <span style="font-size:12px;">- (NSMutableArray *) portraitConstraints:(UIView *)greenView :(UIView *)yellowView :(UIView *)blueView
- {
- NSMutableArray *constraintArray = [NSMutableArray array];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"H:|-20-[greenView]-20-[yellowView(==greenView)]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(greenView, yellowView)]];
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"V:|-20-[greenView]-20-[blueView(==greenView)]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(greenView, blueView)]];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"V:|-20-[yellowView]-20-[blueView(==yellowView)]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(yellowView, blueView)]];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(blueView)]];
-
- return constraintArray;
- }</span>
而後橫屏的約束:
- <span style="font-size:12px;">- (NSMutableArray *) landscapeConstraints:(UIView *)greenView :(UIView *)yellowView :(UIView *)blueView
- {
- NSMutableArray *constraintArray = [NSMutableArray array];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"H:|-20-[greenView]-20-[yellowView(==greenView)]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(greenView, yellowView)]];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"V:|-20-[blueView]-20-[greenView(==blueView)]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(greenView, blueView)]];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"V:|-20-[blueView]-20-[yellowView(==blueView)]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(yellowView, blueView)]];
-
- [constraintArray addObjectsFromArray:[NSLayoutConstraint
- constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nil
- views:NSDictionaryOfVariableBindings(blueView)]];
-
- return constraintArray;
- }</span>
最後還要處理屏幕旋轉:
- <span style="font-size:12px;">- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection
- withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
- {
- [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
-
- [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {
- if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
- NSLog(@"%s----%d", __FUNCTION__, __LINE__);
- [self.view removeConstraints:self.view.constraints];
- [self.view addConstraints:[self landscapeConstraints:self.greenView_ :self.yellowView_ :self.blueView_]];
- } else {
- NSLog(@"%s----%d", __FUNCTION__, __LINE__);
- [self.view removeConstraints:self.view.constraints];
- [self.view addConstraints:[self portraitConstraints:self.greenView_ :self.yellowView_ :self.blueView_]];
- }
- [self.view setNeedsLayout];
- } completion:nil];
- }</span>
這樣就實現了咱們預期的效果,總結下來,auotlayout就是給view添加足夠的約束,讓view系統能夠根據約束來計算出一個view的frame。動手練習一下吧!
二、view動畫在autolayout實現
當佈局發生改變時,至關於對子view進行從新佈局,而子view從新佈局調用 layoutIfNeeded,因此動畫能夠這樣實現:
- <span style="font-size:12px;">- (void)animateConstraints
- {
- [UIView animateWithDuration:0.5 animations:^{
- [self.view layoutIfNeeded];
- }];
- }</span>
Github上已經有
Demo了!
三、autolayout有沒有侷限性和解決不了的問題?兼容性怎麼樣?效率怎麼樣?
autolayout對view transforms支持的很差,這裏有帖子詳細描述了這個問題。
至於兼容性,只從iOS6就已經提出了autolayout的概念,如今iOS5系統不是不少了,甚至iOS6系統都已經升級爲iOS7,將來一段時間大部分用戶應該是使用iOS7和iOS8系統,因此兼容性問題不會太大,但size class是iOS8纔有的概念,因此還有有必定的適配工做量。
效率話題這裏有提到,有時間再細研究。
結束語:時間和體力老是有限的,標題是autolayout詳解,可想達到詳解還須要更多的時間去實踐和總結,還有一些細節沒有體現出來:
例如:
- <span style="font-size:12px;">[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[newView]-20-|"options:0 metrics:nil views:NSDictionaryOfVariableBindings(newView, self.view)]</span>
一、這其中各個參數的含義,另外約束還有個優先級的概念
二、@"H:|-20-[newView]-20-|" 這種可視化佈局字符串的含義等等,有空再補充了!
本篇內容全部Demo
歡迎指出錯誤,不勝感激。