iOS8開發~UI佈局(三)深入理解autolayout

通過對iOS8界面佈局的學習和總結,發現autolayout纔是主角,autolayout是iOS6引入的新特性,當時還粗淺的學習了下,可是沒有真正應用到項目中。隨着iOS設備尺寸逐漸碎片化,純粹的hard code方式UI佈局將會走向死角,而autoresizing方式也有其侷限性,所以無論如何autolayout都將成爲UI佈局的重要方式。

前兩篇以發燒友心態對iOS8界面佈局的主要元素size class和autolayout進行了探索,發現要完全掌握autolayout需要大量的時間去實踐總結。所以深入思考autolayout是很有必要的。你可能有和我同樣的疑問,如下:

1、以後一律使用autolayout嗎?除了在storyboard中使用autolayout,代碼方式autolayout如何使用?

2、好像忽略了一個重要問題,就是view動畫在autolayout如何實現?

3、autolayout有沒有侷限性和解決不了的問題?兼容性怎麼樣?效率怎麼樣?

4、……

二、研究開始

1、直接說以後都應該使用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)最基本的約束實現方式

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.     // Do any additional setup after loading the view, typically from a nib.  
  4.     self.view.translatesAutoresizingMaskIntoConstraints =NO;  
  5.       
  6.     UIView *newView = [UIView new];  
  7.     newView.backgroundColor = [UIColor greenColor];  
  8.     [self.view addSubview:newView];  
  9.       
  10.     newView.translatesAutoresizingMaskIntoConstraints =NO;  
  11.       
  12.     NSLayoutConstraint *constraint = nil;  
  13.       
  14.     constraint = [NSLayoutConstraint constraintWithItem:newView  
  15.                                               attribute:NSLayoutAttributeLeading  
  16.                                               relatedBy:NSLayoutRelationEqual  
  17.                                                  toItem:self.view  
  18.                                               attribute:NSLayoutAttributeLeading  
  19.                                              multiplier:1.0f  
  20.                                                constant:20];  
  21.     [self.view addConstraint:constraint];  
  22.       
  23.     constraint = [NSLayoutConstraint constraintWithItem:newView  
  24.                                               attribute:NSLayoutAttributeTrailing  
  25.                                               relatedBy:NSLayoutRelationEqual  
  26.                                                  toItem:self.view  
  27.                                               attribute:NSLayoutAttributeTrailing  
  28.                                              multiplier:1.0f  
  29.                                                constant:-20];  
  30.     [self.view addConstraint:constraint];  
  31.       
  32.     constraint = [NSLayoutConstraint constraintWithItem:newView  
  33.                                               attribute:NSLayoutAttributeTop  
  34.                                               relatedBy:NSLayoutRelationEqual  
  35.                                                  toItem:self.view  
  36.                                               attribute:NSLayoutAttributeTop  
  37.                                              multiplier:1.0f  
  38.                                                constant:20];  
  39.     [self.view addConstraint:constraint];  
  40.       
  41.     constraint = [NSLayoutConstraint constraintWithItem:newView  
  42.                                               attribute:NSLayoutAttributeBottom  
  43.                                               relatedBy:NSLayoutRelationEqual  
  44.                                                  toItem:self.view  
  45.                                               attribute:NSLayoutAttributeBottom  
  46.                                              multiplier:1.0f  
  47.                                                constant:-20];  
  48.     [self.view addConstraint:constraint];  
  49.       
  50. }</span>  

(2)特殊格式化語言的約束實現方式

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.     self.view.translatesAutoresizingMaskIntoConstraints =NO;  
  4.       
  5.     UIView *newView = [UIView new];  
  6.     newView.backgroundColor = [UIColor greenColor];  
  7.     [self.view addSubview:newView];  
  8.     newView.translatesAutoresizingMaskIntoConstraints =NO;  
  9.       
  10.     NSMutableArray *constraintArray = [NSMutableArray array];  
  11.       
  12.     [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[newView]-20-|"  
  13.                                                                                  options:0  
  14.                                                                                  metrics:nil  
  15.                                                                                    views:NSDictionaryOfVariableBindings(newView, self.view)]];  
  16.     [constraintArray addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[newView]-20-|"  
  17.                                                                                  options:0  
  18.                                                                                  metrics:nil  
  19.                                                                                    views:NSDictionaryOfVariableBindings(newView, self.view)]];  
  20.     [self.view addConstraints:constraintArray];  
  21. }</span>  

(3)第三方UIView-AutoLayout

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.     self.view.translatesAutoresizingMaskIntoConstraints =NO;  
  4.       
  5.     UIView *newView = [UIView new];  
  6.     newView.backgroundColor = [UIColor greenColor];  
  7.     [self.view addSubview:newView];  
  8.     newView.translatesAutoresizingMaskIntoConstraints =NO;  
  9.       
  10.     [newView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:20.0f];  
  11.     [newView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:20.0f];  
  12.     [newView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:20.0f];  
  13.     [newView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:20.0f];  
  14. }</span>  

以上3種方式都實現了我們想要的效果,看來代碼實現autolayout也不是那麼複雜!


例子2:通過上邊例子我們實現一個簡單的UI佈局,下面來一個稍微複雜點的,把上一篇中提到3個view佈局的那個例子用代碼佈局實現一下,但難度有所增加,當size class切換的時候,頁面佈局發生相應的改變,效果如圖:

            

首先初始化3個View:

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (UIView *) alView {  
  2.     UIView *newView = [UIView new];  
  3.     newView.translatesAutoresizingMaskIntoConstraints =NO;  
  4.       
  5.     return newView;  
  6. }  
  7. UIView *greenView = [self alView];  
  8. greenView.backgroundColor = [UIColor greenColor];  
  9. [self.view addSubview:greenView];  
  10. UIView *yellowView = [self alView];  
  11. yellowView.backgroundColor = [UIColor yellowColor];  
  12. [self.view addSubview:yellowView];  
  13. UIView *blueView = [self alView];  
  14. blueView.backgroundColor = [UIColor blueColor];  
  15. [self.view addSubview:blueView];</span>  

接下來適配豎屏的約束:

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (NSMutableArray *) portraitConstraints:(UIView *)greenView :(UIView *)yellowView :(UIView *)blueView  
  2. {  
  3.     NSMutableArray *constraintArray = [NSMutableArray array];  
  4.       
  5.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  6.                                           constraintsWithVisualFormat:@"H:|-20-[greenView]-20-[yellowView(==greenView)]-20-|" options:0 metrics:nil  
  7.                                           views:NSDictionaryOfVariableBindings(greenView, yellowView)]];  
  8.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  9.                                           constraintsWithVisualFormat:@"V:|-20-[greenView]-20-[blueView(==greenView)]-20-|" options:0 metrics:nil  
  10.                                           views:NSDictionaryOfVariableBindings(greenView, blueView)]];  
  11.       
  12.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  13.                                           constraintsWithVisualFormat:@"V:|-20-[yellowView]-20-[blueView(==yellowView)]-20-|" options:0 metrics:nil  
  14.                                           views:NSDictionaryOfVariableBindings(yellowView, blueView)]];  
  15.       
  16.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  17.                                           constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nil  
  18.                                           views:NSDictionaryOfVariableBindings(blueView)]];  
  19.       
  20.     return constraintArray;  
  21. }</span>  

然後橫屏的約束:

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (NSMutableArray *) landscapeConstraints:(UIView *)greenView :(UIView *)yellowView :(UIView *)blueView  
  2. {  
  3.     NSMutableArray *constraintArray = [NSMutableArray array];  
  4.       
  5.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  6.                                           constraintsWithVisualFormat:@"H:|-20-[greenView]-20-[yellowView(==greenView)]-20-|" options:0 metrics:nil  
  7.                                           views:NSDictionaryOfVariableBindings(greenView, yellowView)]];  
  8.       
  9.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  10.                                           constraintsWithVisualFormat:@"V:|-20-[blueView]-20-[greenView(==blueView)]-20-|" options:0 metrics:nil  
  11.                                           views:NSDictionaryOfVariableBindings(greenView, blueView)]];  
  12.       
  13.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  14.                                           constraintsWithVisualFormat:@"V:|-20-[blueView]-20-[yellowView(==blueView)]-20-|" options:0 metrics:nil  
  15.                                           views:NSDictionaryOfVariableBindings(yellowView, blueView)]];  
  16.       
  17.     [constraintArray addObjectsFromArray:[NSLayoutConstraint  
  18.                                           constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nil  
  19.                                           views:NSDictionaryOfVariableBindings(blueView)]];  
  20.       
  21.     return constraintArray;  
  22. }</span>  

最後還要處理屏幕旋轉:

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection  
  2.               withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator  
  3. {  
  4.     [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];  
  5.       
  6.     [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {  
  7.         if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {  
  8.             NSLog(@"%s----%d", __FUNCTION__, __LINE__);  
  9.             [self.view removeConstraints:self.view.constraints];  
  10.             [self.view addConstraints:[self landscapeConstraints:self.greenView_ :self.yellowView_ :self.blueView_]];  
  11.         } else {  
  12.             NSLog(@"%s----%d", __FUNCTION__, __LINE__);  
  13.             [self.view removeConstraints:self.view.constraints];  
  14.             [self.view addConstraints:[self portraitConstraints:self.greenView_ :self.yellowView_ :self.blueView_]];  
  15.         }  
  16.         [self.view setNeedsLayout];  
  17.     } completion:nil];  
  18. }</span>  

這樣就實現了我們預期的效果,總結下來,auotlayout就是給view添加足夠的約束,讓view系統可以根據約束來計算出一個view的frame。動手練習一下吧!


2、view動畫在autolayout實現

當佈局發生改變時,相當於對子view進行重新佈局,而子view重新佈局調用 layoutIfNeeded,所以動畫可以這樣實現:

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">- (void)animateConstraints  
  2. {  
  3.     [UIView animateWithDuration:0.5 animations:^{  
  4.         [self.view layoutIfNeeded];  
  5.     }];  
  6. }</span>  

Github上已經有Demo了!


3、autolayout有沒有侷限性和解決不了的問題?兼容性怎麼樣?效率怎麼樣?

autolayout對view transforms支持的不好,這裏有帖子詳細描述了這個問題。

至於兼容性,只從iOS6就已經提出了autolayout的概念,現在iOS5系統不是很多了,甚至iOS6系統都已經升級爲iOS7,未來一段時間大部分用戶應該是使用iOS7和iOS8系統,所以兼容性問題不會太大,但size class是iOS8纔有的概念,所以還有有一定的適配工作量。

效率話題這裏有提到,有時間再細研究。


結束語:時間和體力總是有限的,標題是autolayout詳解,可想達到詳解還需要更多的時間去實踐和總結,還有一些細節沒有體現出來:

例如:

[objc] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:12px;">[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[newView]-20-|"options:0 metrics:nil views:NSDictionaryOfVariableBindings(newView, self.view)]</span>  

1、這其中各個參數的含義,另外約束還有個優先級的概念

2、@"H:|-20-[newView]-20-|" 這種可視化佈局字符串的含義等等,有空再補充了!

本篇內容所有Demo

歡迎指出錯誤,不勝感激。

轉自:http://blog.csdn.net/liangliang103377/article/details/40082271

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章