关于iOS自动布局

来源:互联网 发布:查询手机号数据库 编辑:程序博客网 时间:2024/05/20 06:06

这里做一个通过代码实现自动布局的Demo,通过IB来做的就不讲了,网上相关的资料很多,这里给出一个写的不错的链接,有兴趣的同学自己看吧.

iOS7自动布局教程(一)

iOS7自动布局教程(二)   --英文


要谈自动布局,那基本的视图是第一步,做了一个这样的ViewController

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">//  
  2. //  NESMainViewController.m  
  3. //  AutoLayout  
  4. //  
  5. //  Created by Nestor on 14-3-2.  
  6. //  Copyright (c) 2014年 NesTalk. All rights reserved.  
  7. //  
  8.   
  9. #import "NESMainViewController.h"  
  10.   
  11. @interface NESMainViewController ()  
  12.   
  13. @property (nonatomic,retainUIView *view1;  
  14. @property (nonatomic,retainUIView *view2;  
  15. @property (nonatomic,retainUIView *view3;  
  16.   
  17. @end  
  18.   
  19. @implementation NESMainViewController  
  20.   
  21. -(UIView *)view1  
  22. {  
  23.     if (!_view1) {  
  24.         _view1 = [[UIView alloc] initWithFrame:CGRectMake(1030145200)];  
  25.         _view1.backgroundColor = [UIColor greenColor];  
  26.     }  
  27.     return _view1;  
  28. }  
  29.   
  30. -(UIView *)view2  
  31. {  
  32.     if (!_view2) {  
  33.         _view2 = [[UIView alloc] initWithFrame:CGRectMake(16530145200)];  
  34.         _view2.backgroundColor = [UIColor yellowColor];  
  35.     }  
  36.     return _view2;  
  37. }  
  38.   
  39. -(UIView *)view3  
  40. {  
  41.     if (!_view3) {  
  42.         _view3 = [[UIView alloc] initWithFrame:CGRectMake(10240300300)];  
  43.         _view3.backgroundColor = [UIColor blueColor];  
  44.     }  
  45.     return _view3;  
  46. }  
  47.   
  48. -(void)buildLayout  
  49. {  
  50.     [self.view addSubview:self.view1];  
  51.     [self.view addSubview:self.view2];  
  52.     [self.view addSubview:self.view3];  
  53. }  
  54.   
  55. - (void)viewDidLoad  
  56. {  
  57.     [super viewDidLoad];  
  58.     [self buildLayout];  
  59. }  
  60.   
  61. - (void)didReceiveMemoryWarning  
  62. {  
  63.     [super didReceiveMemoryWarning];  
  64.     // Dispose of any resources that can be recreated.  
  65. }  
  66.   
  67. @end  
  68. </span>  


看完这个类,有必要先说一下我的代码风格,对于很多刚刚做iOS开发不久的程序员看这部分代码可能感觉很麻烦~但是按照这种风格进行编码是有很大好处的.

先看这段代码

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">-(UIView *)view1  
  2. {  
  3.     if (!_view1) {  
  4.         _view1 = [[UIView alloc] initWithFrame:CGRectMake(1030145200)];  
  5.         _view1.backgroundColor = [UIColor greenColor];  
  6.     }  
  7.     return _view1;  
  8. }</span>  


这段代码的写法经常能够看到,单例里面有他,TableView的代理方法能用到他,这里属于重写@property的getter方法,简单来说,通过点语法来调用私有成员变量:self.view1来调用该方法,有两大好处

1.分离了不同方法的构造内容,代码层次更加明显.

2.延迟加载,什么时候需要什么时候创建,而不是统一在ViewDidLoad方法中进行创建,对于复杂的视图控制器来说可以优化运行效率.


再看ViewDidLoad方法里

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">- (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.     [self buildLayout];  
  5. }</span>  

非常简单,调用了一个buildLayout方法,看方法名就能够知道,这里是专门用来初始化视图布局的方法,由于在oc中init开头的方法被看做类的初始化方法,故此使用了build,当然这属于个人习惯,无所谓的事~


buildLayout方法则逐个将要添加的控件放到了view上

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">-(void)buildLayout  
  2. {  
  3.     [self.view addSubview:self.view1];  
  4.     [self.view addSubview:self.view2];  
  5.     [self.view addSubview:self.view3];  
  6. }</span>  

这里就能够明显的看到通过重写getter方法来初始化视图的好处了,都添加了哪些控件一目了然,如果需要修改某一个控件,那直接定位到对应的getter方法修改即可,而无需在大量的代码中搜索那么几行代码.


根据这样的代码布局进行编写,对于单一视图控制器来说,就可以有了这样的分层效果:



闲话到这,继续主题.


代码到这里屏幕上的视图应该如下图所示



是我们需要的布局效果,但是如果屏幕横过来,问题就出现了



接下来就需要对代码进行一定的调整来完成自动布局.

从iOS6开始...应该是这时候开始吧,想不起来了,加入了NSLayoutConstraint,这个就是做自动布局需要用到的东西


在使用NSLayoutConstraint的时候需要用到一种Visual Format Language,不是特别难的东西,本文的Demo里会简单介绍,更深层的东西有兴趣自己搜索一下吧.


首先需要在

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">-(UIView *)view1  
  2. {  
  3.     if (!_view1) {  
  4.         _view1 = [[UIView alloc] initWithFrame:CGRectMake(1030145200)];  
  5.         _view1.backgroundColor = [UIColor greenColor];  
  6.     }  
  7.     return _view1;  
  8. }</span>  
以及其他方法中添加如下代码:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">        _view1.translatesAutoresizingMaskIntoConstraints = NO;</span>  
用来禁止AutoresizingMask转换成AutoLayout,简单来说,Autoresizing和AutoLayout用的不是一套东西,但是默认情况下是相互转换的,这里我们要指定使用AutoLayout系统,所以要禁止自动转换


跟着在buildLayout方法中添加下列内容:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">    NSDictionary *views = NSDictionaryOfVariableBindings(self.view,_view3,_view2,_view1);  
  2.       
  3.     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_view1(==_view2)]-10-[_view2]-10-|" options:0 metrics:0 views:views]];  
  4.     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[_view1(<=200)]-10-[_view3]-10-|" options:0 metrics:0 views:views]];  
  5.     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[_view2(<=200)]-10-[_view3]-10-|" options:0 metrics:0 views:views]];  
  6.     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_view3]-10-|" options:0 metrics:0 views:views]];  
  7.     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_view3(>=150)]-10-|" options:0 metrics:0 views:views]];</span>  

一步一步看:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">    NSDictionary *views = NSDictionaryOfVariableBindings(self.view,_view3,_view2,_view1);</span>  
这里用到了一个系统宏定义,NSDictionaryOfVariableBindings(),其作用是生成一个词典,key的名字和对象的标识符相同,以上述为例,生成的词典形式就是{"self.view":self.view,@"_view3":_view3,...},这个词典应当包含需要自动布局的父视图和所有的子视图,

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[_view1(==_view2)]-10-[_view2]-10-|" options:0 metrics:0 views:views]];</span>  
这里则是添加了一条自动布局规则,可以看到有个比较麻烦的字符串参数,简单解释一下

| 屏幕的边框

-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的初始化方法可以改写成:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">-(UIView *)view1  
  2. {  
  3.     if (!_view1) {  
  4.         _view1 = [[UIView alloc] init];  
  5.         _view1.backgroundColor = [UIColor greenColor];  
  6.         _view1.translatesAutoresizingMaskIntoConstraints = NO;  
  7.     }  
  8.     return _view1;  
  9. }</span>  

由此便完成了整个视图的自动布局,还是非常容易实现的,就个人而言,通过代码来进行自动布局比xib要方便的多.大家可以自行选择.


如果在view1中需要添加子view同样需要自动布局呢?看看下列代码,非常简单:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:18px;">-(UIView *)view1  
  2. {  
  3.     if (!_view1) {  
  4.         _view1 = [[UIView alloc] init];  
  5.         _view1.backgroundColor = [UIColor greenColor];  
  6.         _view1.translatesAutoresizingMaskIntoConstraints = NO;  
  7.           
  8.         UIView *view = [[UIView alloc] init];  
  9.         view.backgroundColor = [UIColor magentaColor];  
  10.         [_view1 addSubview:view];  
  11.         view.translatesAutoresizingMaskIntoConstraints = NO;  
  12.         NSDictionary *views = NSDictionaryOfVariableBindings(_view1,view);  
  13.         [_view1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[view]-10-|" options:0 metrics:0 views:views]];  
  14.         [_view1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[view]-10-|" options:0 metrics:0 views:views]];  
  15.           
  16.     }  
  17.     return _view1;  
  18. }</span>  

好了,到这里自动布局就差不多了,效果图如下:



原文链接:http://blog.csdn.net/nestalk/article/details/20292623

0 0
原创粉丝点击