ios 自動佈局

自動佈局,那基本的視圖是第一步,做了一個這樣的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


看完這個類,有必要先說一下我的代碼風格,對於很多剛剛做iOS開發不久的程序員看這部分代碼可能感覺很麻煩~但是按照這種風格進行編碼是有很大好處的.

先看這段代碼

-(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方法修改即可,而無需在大量的代碼中搜索那麼幾行代碼.


根據這樣的代碼佈局進行編寫,對於單一視圖控制器來說,就可以有了這樣的分層效果:



閒話到這,繼續主題.


代碼到這裏屏幕上的視圖應該如下圖所示



是我們需要的佈局效果,但是如果屏幕橫過來,問題就出現了



接下來就需要對代碼進行一定的調整來完成自動佈局.

從iOS6開始...應該是這時候開始吧,想不起來了,加入了NSLayoutConstraint,這個就是做自動佈局需要用到的東西


在使用NSLayoutConstraint的時候需要用到一種Visual Format Language,不是特別難的東西,本文的Demo裏會簡單介紹,更深層的東西有興趣自己搜索一下吧.


首先需要在

-(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;
}

由此便完成了整個視圖的自動佈局,還是非常容易實現的,就個人而言,通過代碼來進行自動佈局比xib要方便的多.大家可以自行選擇.


如果在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;
}

好了,到這裏自動佈局就差不多了,效果圖如下:



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