1 使用Autoresizing的方式进行界面布局
1.1 问题
Autoresizing是IOS旧版的自动布局技术,现在仍然被很多企业使用。本案例将学习如何使用Autoresizing完成界面的布局,如图-1、图-2所示:
图-1
图-2
1.2 方案
首先创建一个SingleViewApplication项目,会自动帮我们创建好一个TRViewController类,并且自动带有Storyboard文件,默认情况下Storyboard里面有一个已经创建好的场景,已和TRViewController类绑定。
由于Autoresizing和自动布局是冲突的,所以首先将自动布局功能关闭,选中Storyboard中的场景,在右边栏的第一个检查器中将Use AutoLayout和Use Size classes选项前面的勾去掉;
其次设置界面,在Storyboard的场景的上方拖放两个Button控件,中间拖放一个ImageView,右下角拖放三个小的Button控件。
然后依次选中场景中各个控件,在右边栏的第五个检查器中进行Autoresizing的布局设置,根据界面需要点亮需要的红线;
最后使用代码方式补充Autoresizing无法完成的布局任务。
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,关闭自动布局功能
首先创建一个SingleViewApplication项目,Xcode会自动帮我们创建好一个TRViewController类,并且自动带有Storyboard文件。默认情况下Storyboard里面有一个已经创建好的场景,并且已经和TRViewController类绑定。
由于Autoresizing和自动布局是冲突的,所以首先将自动布局功能关闭,选中Storyboard中的场景,在右边栏的第一个检查器中将Use Auto Layout和Use Size classes选项前面的勾去掉,如图-3所示:
图-3
步骤二:设置界面
首先在Storyboard的场景拖放两个Button控件,两个Button的大小一样,并排放置在场景的上方。
然后界面中间拖放一个ImageView,给ImageView设置一张图片。界面的右下角拖放三个小的Button控件,大小也保持一致,界面完成构建如图-4所示:
图-4
步骤三:设置Autoresizing,进行布局
首先选中场景中左上方的Button的控件,在右边栏的第五个检查器中进行Autoresizing的布局设置,根据界面需要,点亮Button左边、上方的红线,表示Button控件相对于父视图保持左边距和上边距不变。然后在点亮Button中间的横线,表示Button的宽是控件的宽度随着父视图的宽度按比例改变,如图-5所示:
图-5
再选中场景中右上方的Button的控件,同样在右边栏的第五个检查器中进行Autoresizing的布局设置,根据界面需要,点亮Button右边、上方的红线,表示Button控件相对于父视图保持右边距和上边距不变。然后在点亮Button中间的横线,表示Button的宽是可以随视图变化而变化的,如图-6所示:
图-6
然后依照同样的步骤,设置ImageView的Autoresizing,对ImageView进行布局设置,使ImageView始终保持在屏幕中间显示,如图-7所示:
图-7
最后设置右下角三个Button的Autoresizing,使这个三个button始终保持在屏幕的右下角,并且间距和大小保持不变,如图-8所示:
图-8
步骤四:使用代码完成其他布局要求
Autoresizing只能描述子视图与父视图之间的关系,并不能描述子视图之间的布局关系,因此在Autoresizing不能满足布局要求的时候,需要使用代码来补充完成,本案例中当完成了如上的Autoresizing设置之后,将屏幕切换成横屏之后,发现上方两个Button的距离发生了变化,并不是我们想要实现的效果,如图-9所示:
图-9
为了使两个Button之间的距离保持不变,此时只能在TRViewControll类中重写viewDidLayoutSubviews方法,使用代码来完成此项布局设置,代码如下所示:
- - (void)viewDidLayoutSubviews
- {
- [super viewDidLayoutSubviews];
- CGFloat buttonWidth = (self.view.bounds.size.width - 50)/2;
- CGRect frame = CGRectMake(20, 20, buttonWidth, 40);
- self.button1.frame = frame;
- frame.origin.x += buttonWidth + 10;
- self.button2.frame = frame;
- }
这样就能使两个Button之间无论是横屏还是竖屏都能保持固定的间距,最终完成效果如图-10所示:
图-10
1.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIButton *button1;
- @property (weak, nonatomic) IBOutlet UIButton *button2;
- @end
- @implementation TRViewController
- - (void)viewDidLayoutSubviews
- {
- [super viewDidLayoutSubviews];
- CGFloat buttonWidth = (self.view.bounds.size.width - 50)/2;
- CGRect frame = CGRectMake(20, 20, buttonWidth, 40);
- self.button1.frame = frame;
- frame.origin.x += buttonWidth + 10;
- self.button2.frame = frame;
- }
- @end
2 代码方式使用Autoresizing进行界面布局
2.1 问题
当子视图直接是用代码的方式创建时,就无法在Storyboard或xib中对其进行Autosizing的设置和操作,此时就需要用代码的方式使用Autoresizing技术。本案例将学习如何使用代码的方式进行Autoresizing布局,使界面上的两个按钮始终保持在屏幕的右上角和右下角,如图-11、图-12所示:
图-11
图-12
2.2 方案
首先同样的创建一个SingleViewApplication项目,在TRViewController.m文件的viewDidLoad方法中创建两个UIButton控件,分别放置在屏幕的右上角和右下角。
然后通过设置Button的autoresizingMask属性,进行Autoresizing布局,相当于在检查器中点亮Autoresizing的红线。
2.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,添加按钮控件
首先创建一个SingleViewApplication项目。在TRViewController.m文件的viewDidLoad方法中创建两个UIButton控件,分别设置两个button的frame属性,将两个button放置在屏幕的右上角和右下角,代码如下所示:
- UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeSystem];
- btn1.frame = CGRectMake(self.view.bounds.size.width - 20 - 80, self.view.bounds.size.height - 20 - 35, 80, 35);
- btn1.backgroundColor = [UIColor lightGrayColor];
- [self.view addSubview:btn1];
- UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeSystem];
- btn2.frame = CGRectMake(self.view.bounds.size.width - 20 - 80, 20, 80, 35);
- btn2.backgroundColor = [UIColor lightGrayColor];
- [self.view addSubview:btn2];
步骤二:设置Button的autoresizingMask属性,进行Autoresizing布局
通过设置Button的autoresizingMask属性,进行Autoresizing布局,autoresizingMask属性是UIViewAutoresizing的枚举类型。
首先使用代码分别将btn1相对于父视图的上边距和左边距固定,即将btn1.autoresizingMask设置为UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin。
然后使用代码分别将btn2相对于父视图的下边距和左边距固定,即将btn2.autoresizingMask设置为UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin,代码如下所示:
- //设置button的Autoresizing布局属性,将按钮btn1相对于父视图的上边距和左边距固定
- btn1.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
- //将btn2相对于父视图的左边距和下边距固定
- btn2.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin;
2.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeSystem];
- btn1.frame = CGRectMake(self.view.bounds.size.width - 20 - 80, self.view.bounds.size.height - 20 - 35, 80, 35);
- btn1.backgroundColor = [UIColor lightGrayColor];
- [self.view addSubview:btn1];
- UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeSystem];
- btn2.frame = CGRectMake(self.view.bounds.size.width - 20 - 80, 20, 80, 35);
- btn2.backgroundColor = [UIColor lightGrayColor];
- [self.view addSubview:btn2];
- //设置button的Autoresizing布局属性,将按钮btn1相对于父视图的上边距和左边距固定
- btn1.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
- //将btn2相对于父视图的左边距和下边距固定
- btn2.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin;
- }
- @end
3 演示自动布局技术(AutoLayout)
3.1 问题
自动布局技术(AutoLayout)是从iOS6开始的一个新的布局技术,在iOS7中开始广泛使用,从iOS8开始和size classes结合使用。
本案例将学习如何使用自动布局技术(AutoLayout)进行界面布局,如图-13、图-14所示:
图-13
图-14
3.2 方案
首先创建一个SingleViewApplication项目,在Storyboard的场景界面中的左上角、左下角、右上角、右下角和中间分别放置一个Button控件。
然后通过工具依次给每一个Button添加自动布局的约束,完成布局。
3.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,添加按钮控件
首先创建一个SingleViewApplication项目,在Storyboard的场景界面中的左上角、左下角、右上角、右下角和中间分别放置一个Button控件,并在右边栏的检查器四中设置Button的属性,界面搭建完成如图-15所示:
图-15
步骤二:进行自动布局
首先选中Storyboard中的场景,在右边栏的检查器一中将Use Auto Layout和Use Size classes选项勾上(默认情况下是勾上的),如图-16所示:
图-16
然后选中左上角的按钮,点击编辑界面右下方的添加约束工具栏上的第二个按钮,在弹出的窗口上,给按钮添加上边距和左边距的约束(点亮红线即可),点击Add 2 Constraints即完成将约束对象添加到视图上,如图-17所示:
图-17
再选中右上角的按钮,以同样的方式给按钮添加上边距和右边距的约束。然后选中上方的两个按钮,点击编辑界面右下方的添加约束工具栏上的第一个按钮,设置两个按钮的对齐方式水平居中对齐,如图-18所示:
图-18
此时选中按钮,可以在右边的检查器五中查看约束情况,也可以对约束进行编辑和调整,如图-19所示:
图-19
然后按照以上方式设置下方两个按钮的约束和对齐方式。在选中左边上下的两个按钮,将两个按钮的对齐方式设置为垂直居中对齐,如图-20所示:
图-20
右边两个按钮也以同样的方式设置为垂直居中对齐。最后设置中间按钮的布局,始终保持在屏幕的水平中心和垂直中心即可,如图-21所示:
图-21
这样就完成了整个界面的布局设置。
4 代码的方式使用自动布局技术
4.1 问题
当界面上的控件是由代码创建时,此时就只能使用代码的方式对该控件进行布局设置。本案例将学习如何通过代码的方式逐步添加约束,进行自动布局设置,使界面中的按钮始终保持在右上角,如图-22、图-23所示:
图-22
图-23
4.2 方案
首先同样的创建一个SingleViewApplication项目,在TRViewController.m文件的viewDidLoad方法中创建一个UIButton控件,设置相关属性,将按钮放置在屏幕的右上角。
然后确认Use AutoLayout功能被打开,在viewDidLoad方法中用代码将按钮的Autoresizing的翻译功能关闭,如果不将其关闭自动布局会自动将Autoresizing功能翻译成约束,造成约束冲突。
再在viewDidLoad方法中通过NSLayoutConstraint类的工厂方法constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:给button对象创建每一个约束。
最后将约束对象添加到父视图中。
4.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,添加按钮控件
首先创建一个SingleViewApplication项目。在TRViewController.m文件的viewDidLoad方法中创建一个Button控件,并将其添加到父视图中,这里需要注意自动布局功能开启时,在viewDidLoad方法中设置控件的frame属性无效,frame是根据自动布局设置自动计算出来的,代码如下所示:
- UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
- button.backgroundColor = [UIColor lightGrayColor];
- [button setTitle:@"我是按钮" forState:UIControlStateNormal];
- [self.view addSubview:button];
然后在检查器中确认Use AutoLayout功能被打开。在viewDidLoad方法中用代码将按钮的Autoresizing的翻译功能关闭,即将button的translatesAutoresizingMaskIntoConstraints属性设置为NO。如果不将其关闭自动布局会自动将Autoresizing功能翻译成约束,造成约束冲突,代码所示:
- button.translatesAutoresizingMaskIntoConstraints = NO;
步骤二:使用代码的方式添加约束
在viewDidLoad方法中通过NSLayoutConstraint类的工厂方法constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:给button对象创建每一个约束,本案例中需要给button创建四个约束,代码如下所示:
- //距离右边20点:button.right = self.view.right * 1.0 + (-20);
- NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-20];
- //距离上边20点:button.top = self.view.top * 0.0 + 20;
- NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:0.0 constant:20];
- //固定宽度100
- NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0.0 constant:100];
最后将约束添加到父视图中,代码如下所示:
- [self.view addConstraint:constraint1];
- [self.view addConstraint:constraint2];
- [self.view addConstraints:@[constraint3, constraint4]];
4.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
- button.backgroundColor = [UIColor lightGrayColor];
- [button setTitle:@"我是按钮" forState:UIControlStateNormal];
- [self.view addSubview:button];
- //关闭Autoresizing的翻译功能(将Autoresizing的默认值自动翻译成约束)
- button.translatesAutoresizingMaskIntoConstraints = NO;
- //创建约束
- //距离右边20点:button.right = self.view.right * 1.0 + (-20);
- NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-20];
- //距离上边20点:button.top = self.view.top * 0.0 + 20;
- NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:0.0 constant:20];
- //固定宽度100
- NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0.0 constant:100];
- //固定高度40
- NSLayoutConstraint *constraint4 = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:0 constant:40];
- //加入到父视图中
- [self.view addConstraint:constraint1];
- [self.view addConstraint:constraint2];
- [self.view addConstraints:@[constraint3, constraint4]];
- }
- @end
5 使用VFL创建多个约束
5.1 问题
由上一个案例可以看出,逐个创建约束对象会使代码非常的繁琐,IOS提供了一种更简便的方式VFL,即Visual Format Language可视格式化语言帮助我们进行代码创建约束对象,本案例将学习如何使用VFL创建约束对象,如图-24、图-25所示:
图-24
图-25
5.2 方案
首先同样的创建一个SingleViewApplication项目,在TRViewController.m文件的viewDidLoad方法中创建三个UIButton控件button1、button1和button3,设置相关属性,并将按钮添加到父视图中。
然后确认Use AutoLayout功能被打开,同样的在viewDidLoad方法中用代码将按钮的Autoresizing的翻译功能关闭,如果不将其关闭自动布局会自动将Autoresizing功能翻译成约束,造成约束冲突。
再在viewDidLoad方法中通过VFL和工厂方法constraintsWithVisualFormat: options: metrics: views:给每一个button对象创建一组约束对象。
最后将约束对象添加到父视图中。
5.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,添加按钮控件
首先创建一个SingleViewApplication项目。在TRViewController.m文件的viewDidLoad方法中创建三个Button控件,并将其添加到父视图中,这里需要注意自动布局功能开启时,在viewDidLoad方法中设置控件的frame属性无效,frame是根据自动布局设置自动计算出来的,代码如下所示:
- UIButton *button1 = [UIButton buttonWithType:UIButtonTypeSystem];
- button1.backgroundColor = [UIColor lightGrayColor];
- [button1 setTitle:@"Button1" forState:UIControlStateNormal];
- [self.view addSubview:button1];
- UIButton *button2 = [UIButton buttonWithType:UIButtonTypeSystem];
- button2.backgroundColor = [UIColor lightGrayColor];
- [button2 setTitle:@"Button2" forState:UIControlStateNormal];
- [self.view addSubview:button2];
- UIButton *button3 = [UIButton buttonWithType:UIButtonTypeSystem];
- button3.backgroundColor = [UIColor lightGrayColor];
- [button3 setTitle:@"Button3" forState:UIControlStateNormal];
- [self.view addSubview:button3];
然后在检查器中确认Use AutoLayout功能被打开。在viewDidLoad方法中用代码将按钮的Autoresizing的翻译功能关闭,即将button1、button2和button3的translatesAutoresizingMaskIntoConstraints属性设置为NO。如果不将其关闭自动布局会自动将Autoresizing功能翻译成约束,造成约束冲突,代码所示:
- button1.translatesAutoresizingMaskIntoConstraints = NO;
- button2.translatesAutoresizingMaskIntoConstraints = NO;
- button3.translatesAutoresizingMaskIntoConstraints = NO;
步骤二:使用VFL创建约束
通过VFL和工厂方法constraintsWithVisualFormat: options: metrics: views:给每一个button对象创建一组约束对象,先给三个按钮创建水平约束,代码如下所示:
- //创建VFL字符串
- NSString *VFLString = @"|-20-[b1]-10-[b2(==b1)]-10-[b3(==b2)]-20-|";
- //根据VFL创建一组约束对象
- NSArray *constraits = [NSLayoutConstraint constraintsWithVisualFormat:VFLString options:NSLayoutFormatAlignAllCenterY metrics:nil views:@{@"b1":button1, @"b2":button2, @"b3":button3}];
- //将约束添加到父视图中
- [self.view addConstraints:constraits];
然后再创建垂直约束,代码如下所示:
- //创建VFL字符串,V表示垂直约束
- VFLString = @"V:|-20-[b1]";
- //根据VFL字符串创建约束对象
- constraits = [NSLayoutConstraint constraintsWithVisualFormat:VFLString options:0 metrics:nil views:@{@"b1":button1}];
- //将约束对象添加到父视图中
- [self.view addConstraints:constraits];
5.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIButton *button1 = [UIButton buttonWithType:UIButtonTypeSystem];
- button1.backgroundColor = [UIColor lightGrayColor];
- [button1 setTitle:@"Button1" forState:UIControlStateNormal];
- [self.view addSubview:button1];
- UIButton *button2 = [UIButton buttonWithType:UIButtonTypeSystem];
- button2.backgroundColor = [UIColor lightGrayColor];
- [button2 setTitle:@"Button2" forState:UIControlStateNormal];
- [self.view addSubview:button2];
- UIButton *button3 = [UIButton buttonWithType:UIButtonTypeSystem];
- button3.backgroundColor = [UIColor lightGrayColor];
- [button3 setTitle:@"Button3" forState:UIControlStateNormal];
- [self.view addSubview:button3];
- //1. 关闭Autoresizing的自动翻译
- button1.translatesAutoresizingMaskIntoConstraints = NO;
- button2.translatesAutoresizingMaskIntoConstraints = NO;
- button3.translatesAutoresizingMaskIntoConstraints = NO;
- //2. 创建约束
- NSString *VFLString = @"|-20-[b1]-10-[b2(==b1)]-10-[b3(==b2)]-20-|";
- NSArray *constraits = [NSLayoutConstraint constraintsWithVisualFormat:VFLString options:NSLayoutFormatAlignAllCenterY metrics:nil views:@{@"b1":button1, @"b2":button2, @"b3":button3}];
- //3. 将约束加入到父视图
- [self.view addConstraints:constraits];
- VFLString = @"V:|-20-[b1]";
- constraits = [NSLayoutConstraint constraintsWithVisualFormat:VFLString options:0 metrics:nil views:@{@"b1":button1}];
- [self.view addConstraints:constraits];
- }
- @end