這裡做一個通過代碼實現自動布局的Demo,通過IB來做的就不講了,網上相關的資料很多,這裡給出一個寫的不錯的鏈接,有興趣的同學自己看吧.
iOS7自動布局教程(一)
iOS7自動布局教程(二) --英文
要談自動布局,那基本的視圖是第一步,做了一個這樣的ViewController
// // NESMainViewController.m // AutoLayout // // Created by Nestor on 14-3-2. // Copyright (c) 2014年 NesTalk. All rights reserved. // #import "NESMainViewController.h" @interface NESMainViewController () @property (nonatomic,retain) UIView *view1; @property (nonatomic,retain) UIView *view2; @property (nonatomic,retain) UIView *view3; @end @implementation NESMainViewController -(UIView *)view1 { if (!_view1) { _view1 = [[UIView alloc] initWithFrame:CGRectMake(10, 30, 145, 200)]; _view1.backgroundColor = [UIColor greenColor]; } return _view1; } -(UIView *)view2 { if (!_view2) { _view2 = [[UIView alloc] initWithFrame:CGRectMake(165, 30, 145, 200)]; _view2.backgroundColor = [UIColor yellowColor]; } return _view2; } -(UIView *)view3 { if (!_view3) { _view3 = [[UIView alloc] initWithFrame:CGRectMake(10, 240, 300, 300)]; _view3.backgroundColor = [UIColor blueColor]; } return _view3; } -(void)buildLayout { [self.view addSubview:self.view1]; [self.view addSubview:self.view2]; [self.view addSubview:self.view3]; } - (void)viewDidLoad { [super viewDidLoad]; [self buildLayout]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
先看這段代碼
-(UIView *)view1 { if (!_view1) { _view1 = [[UIView alloc] initWithFrame:CGRectMake(10, 30, 145, 200)]; _view1.backgroundColor = [UIColor greenColor]; } return _view1; }
這段代碼的寫法經常能夠看到,單例裡面有他,TableView的代理方法能用到他,這裡屬於重寫@property的getter方法,簡單來說,通過點語法來調用私有成員變量:self.view1來調用該方法,有兩大好處
1.分離了不同方法的構造內容,代碼層次更加明顯.
2.延遲加載,什麼時候需要什麼時候創建,而不是統一在ViewDidLoad方法中進行創建,對於復雜的視圖控制器來說可以優化運行效率.
再看ViewDidLoad方法裡
- (void)viewDidLoad { [super viewDidLoad]; [self buildLayout]; }
非常簡單,調用了一個buildLayout方法,看方法名就能夠知道,這裡是專門用來初始化視圖布局的方法,由於在oc中init開頭的方法被看做類的初始化方法,故此使用了build,當然這屬於個人習慣,無所謂的事~
buildLayout方法則逐個將要添加的控件放到了view上
-(void)buildLayout { [self.view addSubview:self.view1]; [self.view addSubview:self.view2]; [self.view addSubview:self.view3]; }
這裡就能夠明顯的看到通過重寫getter方法來初始化視圖的好處了,都添加了哪些控件一目了然,如果需要修改某一個控件,那直接定位到對應的getter方法修改即可,而無需在大量的代碼中搜索那麼幾行代碼.
根據這樣的代碼布局進行編寫,對於單一視圖控制器來說,就可以有了這樣的分層效果:
閒話到這,繼續主題.
代碼到這裡屏幕上的視圖應該如下圖所示
是我們需要的布局效果,但是如果屏幕橫過來,問題就出現了
接下來就需要對代碼進行一定的調整來完成自動布局.<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+tNNpT1M2v6rKvC4uLtOmuMPKx9XiyrG68r+qyrywySzP67K7xvDAtMHLLLzTyOvBy05TTGF5b3V0Q29uc3RyYWludCzV4rj2vs3Kx9f219S2r7K8vtbQ6NKq08O1vbXEtqvO9zwvcD4KPHA+PGJyPgo8L3A+CjxwPtTayrnTw05TTGF5b3V0Q29uc3RyYWludLXEyrG68tDo0qrTw7W90rvW1lZpc3VhbCBGb3JtYXQgTGFuZ3VhZ2UssrvKx8zYsfDE0bXEtqvO9yyxvs7EtcREZW1vwO+74bzytaW96cncLLj8ye6y47XEtqvO99PQ0MvIpNfUvLrL0cv30rvPwrDJLjwvcD4KPHA+PGJyPgo8L3A+CjxwPsrXz8jQ6NKq1No8L3A+CjxwPjwvcD4KPHByZSBjbGFzcz0="brush:java;">-(UIView *)view1 { if (!_view1) { _view1 = [[UIView alloc] initWithFrame:CGRectMake(10, 30, 145, 200)]; _view1.backgroundColor = [UIColor greenColor]; } return _view1; }以及其他方法中添加如下代碼:
_view1.translatesAutoresizingMaskIntoConstraints = NO;用來禁止AutoresizingMask轉換成AutoLayout,簡單來說,Autoresizing和AutoLayout用的不是一套東西,但是默認情況下是相互轉換的,這裡我們要指定使用AutoLayout系統,所以要禁止自動轉換
跟著在buildLayout方法中添加下列內容:
NSDictionary *views = NSDictionaryOfVariableBindings(self.view,_view3,_view2,_view1); [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_view1(==_view2)]-10-[_view2]-10-|" options:0 metrics:0 views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[_view1(<=200)]-10-[_view3]-10-|" options:0 metrics:0 views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[_view2(<=200)]-10-[_view3]-10-|" options:0 metrics:0 views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_view3]-10-|" options:0 metrics:0 views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_view3(>=150)]-10-|" options:0 metrics:0 views:views]];
NSDictionary *views = NSDictionaryOfVariableBindings(self.view,_view3,_view2,_view1);這裡用到了一個系統宏定義,NSDictionaryOfVariableBindings(),其作用是生成一個詞典,key的名字和對象的標識符相同,以上述為例,生成的詞典形式就是{"self.view":self.view,@"_view3":_view3,...},這個詞典應當包含需要自動布局的父視圖和所有的子視圖,
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_view1(==_view2)]-10-[_view2]-10-|" options:0 metrics:0 views:views]];這裡則是添加了一條自動布局規則,可以看到有個比較麻煩的字符串參數,簡單解釋一下
| 屏幕的邊框
-10- 10個點的間距
[_view2] 需要布局的控件,這裡的_view2必須和上邊用來生成詞典的標識符完全相同
[_view1(==_view2)] _view1的作用和上邊完全相同,而()裡面的則是限定條件,可以是==某一個空間,或者一個固定的數值,當然,除了==之外還可以使用>=或者<=;
字符串中的每個部分都解釋清楚後,那麼就容易理解多了~這句話完整的意思整理出來就是:
兩個寬度相同的view,其間距是10個點,距離左右邊框的距離也是10個點~
這樣,無論是豎屏還是橫屏,都會按照這樣一個標准來去進行自動布局.
值得注意的是,能夠執行這種布局的view必須通過-(CGSize)intrinsicContentSize方法返回一個有效的CGSize,而UIView默認返回的是0,所以如果只設置了橫向的布局規則那麼UIView是不會顯示在屏幕上的
對於UIView而言,必須同時設置橫向和縱向布局規則或者寫一個繼承自UIView的自定義View然後重寫-(CGSize)intrinsicContentSize才能實現該效果.
但是對於UIButton,UILabel等則不必,設置個橫向的就夠了.
再看下一句:
V:|-30-[_view1(<=200)]-10-[_view3]-10-|
V: 代表的是垂直方向上的布局規則
簡單解釋一下,view1的高度不能大於200點,距離上邊框30個點,與view3的間距是10個點,view3與底邊框的距離是10個點
由此,通過設置view1的高度上限和間距就可以自動計算出view3的高度.其他的布局規則大家自己看一下也就可以明白了.
同時,如果規定了全部子視圖的布局規則,那麼也就沒有必要去設置子視圖的frame了.各個frame的初始化方法可以改寫成:
-(UIView *)view1 { if (!_view1) { _view1 = [[UIView alloc] init]; _view1.backgroundColor = [UIColor greenColor]; _view1.translatesAutoresizingMaskIntoConstraints = NO; } return _view1; }
如果在view1中需要添加子view同樣需要自動布局呢?看看下列代碼,非常簡單:
-(UIView *)view1 { if (!_view1) { _view1 = [[UIView alloc] init]; _view1.backgroundColor = [UIColor greenColor]; _view1.translatesAutoresizingMaskIntoConstraints = NO; UIView *view = [[UIView alloc] init]; view.backgroundColor = [UIColor magentaColor]; [_view1 addSubview:view]; view.translatesAutoresizingMaskIntoConstraints = NO; NSDictionary *views = NSDictionaryOfVariableBindings(_view1,view); [_view1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[view]-10-|" options:0 metrics:0 views:views]]; [_view1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[view]-10-|" options:0 metrics:0 views:views]]; } return _view1; }