一. 屏幕适配历史
- iphone3gs-4s
frame直接写死。 - ipad:autoresizing
根据父控件的frame发生改变,子控件跟着一起改变。 - iphone5-iPhone5s:autolayout
自动布局(是针对xib进行使用的)。 - iPhone6和iphone6p:sizeClass
发现屏幕变得太多样,界面大统一了(是针对storyboard进行使用的)。
更多关于屏幕适配可参考:
一篇文章详解iOS之AutoResizing、AutoLayout、sizeClass来龙去脉
iOS8中SizeClass的使用
二. AutoLayout
1. AutoLayout简介
在以前的iOS程序中,是如何设置布局UI界面的?
- 经常编写大量的坐标计算代码
- 为了保证在3.5 inch和4.0 inch屏幕上都能有完美的UI界面效果,有时还需要分别为两种屏幕编写不同的坐标计算代码(即传说中的“屏幕适配”)。
什么是Autolayout?
- Autolayout是一种“自动布局”技术,专门用来布局UI界面的
- Autolayout自iOS 6开始引入,由于Xcode 4的不给力,当时并没有得到很大推广
- 自iOS 7(Xcode 5)开始,Autolayout的开发效率得到很大的提升
- 苹果官方也推荐开发者尽量使用Autolayout来布局UI界面
- Autolayout能很轻松地解决屏幕适配的问题
关于Autoresizing:
- 在Autolayout之前,有Autoresizing可以作屏幕适配,但局限性较大,有些任务根本无法完成
- 相比之下,Autolayout的功能比Autoresizing强大很多
Autolayout的2个核心概念:
- 参照
- 约束
2. Autolayout的警告和错误
- 警告:黄色向右的箭头
控件的frame不匹配所添加的约束,比如约束控件的宽度为100,而控件现在的宽度是110。 - 错误:红色向右的箭头
缺乏必要的约束,比如只约束了宽度和高度,没有约束具体的位置。 - 两个约束冲突黄色警告
比如,1个约束控件的宽度为100,1个约束控件的宽度为110。
3. 约束添加的原则
在创建约束之后,需要将其添加到作用的view上,在添加时要注意目标view需要遵循以下规则:
- 对于两个同层级view之间的约束关系,添加到它们的父view上
- 对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上
- 对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上
三. VFL语言
什么是VFL语言?
- VFL全称是Visual Format Language,翻译过来是“可视化格式语言”
- VFL是苹果公司为了简化Autolayout的编码而推出的抽象语言
1. 代码实现Autolayout的步骤
- 利用NSLayoutConstraint类创建具体的约束对象
- 添加约束对象到相应的view上
- (void)addConstraint:(NSLayoutConstraint*)constraint;
- (void)addConstraints:(NSArray*)constraints;
- 代码实现Autolayout的注意点
① 要先禁止autoresizing功能,设置view的下面属性为NO。
view.translatesAutoresizingMaskIntoConstraints=NO;
② 添加约束之前,一定要保证相关控件都已经在各自的父控件上。 - 不用再给view设置frame
2. NSLayoutConstraint类
一个NSLayoutConstraint对象就代表一个约束。
创建约束对象的常用方法:
// view1:要约束的控件
// attr1:约束的类型(做怎样的约束)
// relation:与参照控件之间的关系
// view2:参照的控件
// attr2:约束的类型(做怎样的约束)
// multiplier:乘数
// c:常量
+(id)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
3. VFL的使用
使用VFL来创建约束数组
// format:VFL语句
// opts:约束类型
// metrics:VFL语句中用到的具体数值
// views:VFL语句中用到的控件
+ (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
创建一个字典(内部包含VFL语句中用到的控件)的快捷宏定义NSDictionaryOfVariableBindings(...)
VFL示例:
// canelButton宽72,acceptButton宽50,它们之间间距12
H:[cancelButton(72)]-12-[acceptButton(50)]
// wideView宽度大于等于60point,该约束条件优先级为700(优先级最大值为1000,优先级越高的约束越先被满足)
H:[wideView(>=60@700)]
// 竖直方向上,先有一个redBox,其下方紧接一个高度等于redBox高度的yellowBox
V:[redBox]-[yellowBox(==redBox)]
// 水平方向上,Find距离父view左边缘默认间隔宽度,之后是FindNext距离Find间隔默认宽度;再之后是宽度不小于20的FindField,它和FindNext以及父view右边缘的间距都是默认宽度。(竖线“|”表示superview的边缘)
H:|-10-[Find]-[FindNext]-[FindField(>=20)]-|
4. VFL练习
练习①
//添加两个view蓝色在上.红色在下,红色的宽度是蓝色的一半
- (void)test1
{
// 1.添加控件
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
blueView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:blueView];
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
redView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:redView];
// 2.VFL生成约束
NSArray *conts = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nil views:@{@"blueView" : blueView}];
[self.view addConstraints:conts];
//右对齐
NSArray *conts2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[blueView(40)]-20-[redView(==blueView)]" options:NSLayoutFormatAlignAllRight metrics:nil views:@{@"blueView" : blueView, @"redView" : redView}];
[self.view addConstraints:conts2];
//设置红色的宽度是蓝色的一半,(设置一个view是另外一个view的多少倍的时候必须要用下面的方法)
NSLayoutConstraint *redWidth = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0.0];
[self.view addConstraint:redWidth];
}
效果图如下:
练习1.png练习②
//添加两个按钮,左边,右边,下边距离相等都是20
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.添加控件
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
blueView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:blueView];
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
redView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:redView];
// 2.VFL生成约束
NSDictionary *mertrics = @{@"margin" : @20}; // 参数\数值
NSDictionary *views = NSDictionaryOfVariableBindings(blueView, redView);//view
NSArray *conts = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[blueView]-margin-[redView(==blueView)]-margin-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:mertrics views:views];
//NSLayoutFormatAlignAllTop上对齐
NSArray *conts2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[blueView(==blueHeight)]-margin-|" options:0 metrics:@{@"blueHeight" : @40, @"margin" : @20} views:views];
//竖直方向高度相等
[self.view addConstraints:conts];
[self.view addConstraints:conts2];
}
效果图如下:
练习2.png四. 补充
1. 自动包住文字内容
给label添加Autolayout之后,label的尺寸会根据里面的内容自动包裹文字,不会有空白,以前要算,现在不用算了
在没有Autolayout之前,UILabel的文字内容总是居中显示,导致顶部和底部会有一大片空白区域
没有Autolayout.png有了Autolayout之后,UILabel的bounds默认会自动包住所有的文字内容,顶部和底部不再有空缺区域
有了Autolayout.png2. 通过约束添加动画
storyboard里面的控件如下:
添加动画.png代码如下:
// MJViewController.m
#import "MJViewController.h"
@interface MJViewController ()
@property (weak, nonatomic) IBOutlet UILabel *textLabel;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftMargin;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *width;
@property (weak, nonatomic) IBOutlet UIView *redView;
@end
@implementation MJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
self.leftMargin.constant = 100;
self.width.constant = 200;
[UIView animateWithDuration:2.0 animations:^{
[self.view layoutIfNeeded];
[self.redView layoutIfNeeded];
}];
self.textLabel.text = @"sdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlfsdhjkfhkjlsdhkjflhjdsflhjsdlhkjflhjdshjlf";
}
@end
网友评论