3.VFL语言(Visual Format Language:可视化格式语言)
autolayout的2个核心概念: 参照、约束
注意:
如果使用autolayout来约束控件,那frame就失效了,官方也不建议我们再设置frame了 。
如果利用autolayout约束一个控件,和我们以前使用frame约束控件一样,必须设置宽度/高度/X/Y,如果缺少一个约束就会报错,报错有可能会引发一些未知的bug。
如果有红色错误:代表缺少约束,或者约束有冲突(约束可以重复添加 )
如果有黄色警告:代表当前的位置大小和约束的位置大小不一样
在使用autolayout时,最好给每个控件起一个名称,方便阅读
在使用autolayout让某个控件相对于另一个控件约束,一定要在另一个控件周围
iOS8,默认情况下,左右两边会留出一段距离
xib编辑页面autolayout相关约束选项
设置好约束后在各个尺寸,横竖屏下查看效果
下面设置红色视图宽度为蓝色的一半。
同理宽度也可以采取相同方法
在添加目标view约束时会遵循以下规则。(通过代码添加约束时参照该规则)
1)对于两个同层级view之间的约束关系,添加到它们的父view上
2)对于两个不同层级view之间的约束关系,添加到他们最近的共同父view上(父view不同,继续找父view的父view...)
3)对于有层次关系的两个view之间的约束关系,添加到层次较高的父view上
- (void)viewDidLoad { [super viewDidLoad]; //添加2个控件到父控件上 //添加蓝色view UIView *blueView=[[UIView alloc] init]; blueView.backgroundColor=[UIColor blueColor]; //禁用autoresizing blueView.translatesAutoresizingMaskIntoConstraints=NO; [self.view addSubview:blueView]; //添加红色view UIView *redView=[[UIView alloc] init]; redView.backgroundColor=[UIColor redColor]; //禁用autoresizing redView.translatesAutoresizingMaskIntoConstraints=NO; [self.view addSubview:redView]; //添加约束 //添加蓝色View距离父控件左边的距离固定为20 x /* item == first item 需要设置约束的控件 attribute == 需要设置的约束 relatedBy == relation 等于 toItem == second item 被参照的控件 attribute == 需要设置的约束 multiplier == multiplier 乘以 constant == constant 加上 */ //蓝色view的左边等于父控件的左边乘以1加20 NSLayoutConstraint *leftCos=[NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.viewattribute:NSLayoutAttributeLeft multiplier:1.0f constant:20]; [self.view addConstraint:leftCos]; //添加蓝色View距离父控件右边的距离固定为20 宽度 NSLayoutConstraint *rightCos=[NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.viewattribute:NSLayoutAttributeRight multiplier:1.0f constant:-20]; [self.view addConstraint:rightCos]; //添加蓝色View距离父控件顶部边的距离固定为20 y NSLayoutConstraint *topCos=[NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.viewattribute:NSLayoutAttributeTop multiplier:1.0f constant:20]; [self.view addConstraint:topCos]; //添加蓝色View的高度50 高度 NSLayoutConstraint *heightCos=[NSLayoutConstraintconstraintWithItem:blueView attribute:NSLayoutAttributeHeightrelatedBy:NSLayoutRelationEqual toItem:nilattribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:50]; [blueView addConstraint:heightCos]; //设置红色约束 //红色高度和蓝色一样 height NSLayoutConstraint *redHeightCos=[NSLayoutConstraintconstraintWithItem:redView attribute:NSLayoutAttributeHeightrelatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeHeightmultiplier:1.0f constant:0]; [self.view addConstraint:redHeightCos]; //红色的右边和蓝色右边对齐 x NSLayoutConstraint *redRightCos=[NSLayoutConstraintconstraintWithItem:redView attribute:NSLayoutAttributeRightrelatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeRightmultiplier:1.0f constant:0]; [self.view addConstraint:redRightCos]; //红色的顶部和蓝色底部距离固定20 y NSLayoutConstraint *redTopCos=[NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:20]; [self.view addConstraint:redTopCos]; //红色宽度等于蓝色宽度一半 NSLayoutConstraint *redWidthCos=[NSLayoutConstraintconstraintWithItem:redView attribute:NSLayoutAttributeWidthrelatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeWidthmultiplier:0.5f constant:0]; [self.view addConstraint:redWidthCos]; }
VFL语言(Visual Format Language:可视化格式语言)
VFL语言是苹果公司为了简化Autolayout的编码而推出的抽象语言
- H:[cancelButton(72)]-12-[acceptButton(50)]
- canelButton宽72,acceptButton宽50,它们之间水平间距12
- H:[wideView(>=60@700)]
- wideView宽度大于等于60point,该约束条件优先级为700(优先级最大值为1000,优先级越高的约束越先被满足)
- V:[redBox]-[yellowBox(==redBox)]
- 竖直方向上,先有一个redBox,其下方紧接一个高度等于redBox高度的yellowBox
- H:|-10-[Find]-[FindNext]-[FindField(>=20)]-|
- 水平方向上,Find距离父view左边缘默认间隔宽度10,之后是FindNext距离Find间隔默认宽度0;再之后是宽度不小于20的FindField,它和FindNext以及父view右边缘的间距都是默认宽度。(竖线“|” 表示superview的边缘)
- (void)viewDidLoad { [super viewDidLoad]; //添加2个控件到父控件上 //添加蓝色view UIView *blueView=[[UIView alloc] init]; blueView.backgroundColor=[UIColor blueColor]; //禁用autoresizing blueView.translatesAutoresizingMaskIntoConstraints=NO; [self.view addSubview:blueView]; //添加红色view UIView *redView=[[UIView alloc] init]; redView.backgroundColor=[UIColor redColor]; //禁用autoresizing redView.translatesAutoresizingMaskIntoConstraints=NO; [self.view addSubview:redView]; //添加约束 /* VisualFormat:VFL语句 options:对齐方式 metrics:VFL语句中用到的变量值 views:VFL语句中用到的控件 */ //blueView水平方向距离两边各20距离,设置了x值和宽度 NSArray *blueViewHorizontal=[NSLayoutConstraintconstraintsWithVisualFormat:@"H:|-20-[blueView]-20-|" options:0 metrics:nilviews:@{@"blueView":blueView}]; [self.view addConstraints:blueViewHorizontal]; //blueView垂直方向距离顶部20距离,高度50 ,blueView底部距离redView为20距离 redView高度==blueView;并且设置红色和蓝色右边对齐 NSArray *blueViewVertical=[NSLayoutConstraintconstraintsWithVisualFormat:@"V:|-20-[blueView(50)]-20-[redView(==blueView)]"options:NSLayoutFormatAlignAllRight metrics:nilviews:@{@"blueView":blueView,@"redView":redView}]; [self.view addConstraints:blueViewVertical]; //注意:在VFL语句中是不支持乘除法,要用autolayout代码实现 // NSArray *redViewHorizontal=[NSLayoutConstraint constraintsWithVisualFormat:@"H:[redView(==blueView)]" options:0 metrics:nil views:@{@"blueView":blueView,@"redView":redView}]; // [self.view addConstraints:redViewHorizontal]; NSLayoutConstraint *redViewW=[NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:blueView attribute:NSLayoutAttributeWidth multiplier:0.5 constant:0]; [self.view addConstraint:redViewW]; }
//示例:UIScrollView上使用VFL约束,可滚动
// // ViewController.m // MQTTSDKLearn // // Created by Vie on 2017/3/3. // Copyright © 2017年 Vie. All rights reserved. // #import "ViewController.h" @interface ViewController () @property (nonatomic, strong)MQTTSession *mqttSession; @property (nonatomic, strong)UIScrollView *scrollView;//滚动视图 @property (nonatomic, strong)UITextField *userNameField;//账号输入框 @property (nonatomic, strong)UITextField *passwordField;//密码输入框 @property (nonatomic, strong)UITextField *ipField;//ip输入框 @property (nonatomic, strong)UITextField *portField;//端口号输入框 @property (nonatomic, strong)UIButton *loginBtn;//登陆按钮 @end @implementation ViewController #pragma mark LazyLoading -(UIScrollView *)scrollView{ if (!_scrollView) { _scrollView=[[UIScrollView alloc] init]; _scrollView.translatesAutoresizingMaskIntoConstraints=false; //设置垂直指示滚动标不可见 _scrollView.showsVerticalScrollIndicator = NO; } return _scrollView; } -(UITextField *)userNameField{ if (!_userNameField) { _userNameField=[[UITextField alloc] init]; _userNameField.translatesAutoresizingMaskIntoConstraints=false; _userNameField.layer.borderWidth=1.0; _userNameField.layer.borderColor=[UIColor blackColor].CGColor; [_userNameField.layer setCornerRadius:5.0f]; _userNameField.placeholder=@"请输入用户名"; _userNameField.text=@"admin"; } return _userNameField; } -(UITextField *)passwordField{ if (!_passwordField) { _passwordField=[[UITextField alloc] init]; _passwordField.translatesAutoresizingMaskIntoConstraints=false; _passwordField.layer.borderWidth=1.0; _passwordField.layer.borderColor=[UIColor blackColor].CGColor; [_passwordField.layer setCornerRadius:5.0f]; _passwordField.placeholder=@"请输入密码"; _passwordField.text=@"admin"; } return _passwordField; } -(UITextField *)ipField{ if (!_ipField) { _ipField=[[UITextField alloc] init]; _ipField.translatesAutoresizingMaskIntoConstraints=false; _ipField.layer.borderWidth=1.0; _ipField.layer.borderColor=[UIColor blackColor].CGColor; [_ipField.layer setCornerRadius:5.0f]; _ipField.placeholder=@"请输入IP地址"; _ipField.text=@"10.4.145.68"; } return _ipField; } -(UITextField *)portField{ if (!_portField) { _portField=[[UITextField alloc] init]; _portField.translatesAutoresizingMaskIntoConstraints=false; _portField.layer.borderWidth=1.0; _portField.layer.borderColor=[UIColor blackColor].CGColor; [_portField.layer setCornerRadius:5.0f]; _portField.placeholder=@"请输入端口号"; _portField.text=@"1884"; } return _portField; } -(UIButton *)loginBtn{ if (!_loginBtn) { _loginBtn=[[UIButton alloc] init]; _loginBtn.translatesAutoresizingMaskIntoConstraints=false; [_loginBtn setTitle:@"登 录 订 阅" forState:UIControlStateNormal]; [_loginBtn setBackgroundColor:[UIColor colorWithRed:104/255.0 green:200/255.0 blue:250/255.0 alpha:1]]; [_loginBtn.layer setCornerRadius:8.0f]; [_loginBtn addTarget:self action:@selector(connectAction:) forControlEvents:UIControlEventTouchUpInside]; } return _loginBtn; } #pragma mark viewLoad - (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.scrollView]; [self.scrollView addSubview:self.userNameField]; [self.scrollView addSubview:self.passwordField]; [self.scrollView addSubview:self.ipField]; [self.scrollView addSubview:self.portField]; [self.scrollView addSubview:self.loginBtn]; [self layoutVFL]; } -(void)layoutVFL{ /*最底部或最旁边一个视图要确定与_scrollView的位置关系,这样_scrollView才能确定contenSize是否滑动*/ /*滚动视图水平约束*/ NSArray *scrollViewHorizotal=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[_scrollView]-0-|" options:0 metrics:nil views:@{@"_scrollView":_scrollView}]; [self.view addConstraints:scrollViewHorizotal]; /*滚动视图垂直约束*/ NSArray *scrollViewViertical=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[_scrollView]-0-|" options:0 metrics:nil views:@{@"_scrollView":_scrollView}]; [self.view addConstraints:scrollViewViertical]; /*用户名宽度约束,_userNameField宽度=_scrollView的1.0倍-60*/ NSLayoutConstraint *fieldWidth=[NSLayoutConstraint constraintWithItem:_userNameField attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_scrollView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:-60]; [self.scrollView addConstraint:fieldWidth]; //添加_userNameField距离父控件右边的距离固定为20 宽度 NSLayoutConstraint *rightCos=[NSLayoutConstraint constraintWithItem:_userNameField attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:_scrollView attribute:NSLayoutAttributeRight multiplier:1.0f constant:-30]; [self.scrollView addConstraint:rightCos]; //_userNameField的左边等于父控件的左边乘以1加20 NSLayoutConstraint *leftCos=[NSLayoutConstraint constraintWithItem:_userNameField attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_scrollView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:30]; [self.scrollView addConstraint:leftCos]; /*用户名垂直方向约束*/ NSArray *userNameFieldViertical=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[_userNameField(45)]" options:0 metrics:nil views:@{@"_userNameField":_userNameField}]; [self.scrollView addConstraints:userNameFieldViertical]; /*密码输入框水平约束*/ NSArray *passwordFieldHorizotal=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-30-[_passwordField(==_userNameField)]" options:0 metrics:nil views:@{@"_passwordField":_passwordField,@"_userNameField":_userNameField}]; [self.scrollView addConstraints:passwordFieldHorizotal]; /*密码输入框垂直约束*/ NSArray *passwordFieldViertical=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_userNameField]-30-[_passwordField(==_userNameField)]" options:0 metrics:nil views:@{@"_passwordField":_passwordField,@"_userNameField":_userNameField}]; [self.scrollView addConstraints:passwordFieldViertical]; /*ip输入框水平约束*/ NSArray *ipFieldHorizotal=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-30-[_ipField(==_passwordField)]" options:0 metrics:nil views:@{@"_passwordField":_passwordField,@"_ipField":_ipField}]; [self.scrollView addConstraints:ipFieldHorizotal]; /*ip输入框垂直约束*/ NSArray *ipFieldViertical=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_passwordField]-30-[_ipField(==_passwordField)]" options:0 metrics:nil views:@{@"_passwordField":_passwordField,@"_ipField":_ipField}]; [self.scrollView addConstraints:ipFieldViertical]; /*端口输入框水平约束*/ NSArray *portFieldHorizotal=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-30-[_portField(==_ipField)]" options:0 metrics:nil views:@{@"_ipField":_ipField,@"_portField":_portField}]; [self.scrollView addConstraints:portFieldHorizotal]; /*端口输入框垂直约束*/ NSArray *portFieldViertical=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_ipField]-30-[_portField(==_ipField)]" options:0 metrics:nil views:@{@"_ipField":_ipField,@"_portField":_portField}]; [self.scrollView addConstraints:portFieldViertical]; /*登录按钮水平约束*/ NSArray *loginBtnHorizotal=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-30-[_loginBtn(==_portField)]" options:0 metrics:nil views:@{@"_loginBtn":_loginBtn,@"_portField":_portField}]; [self.scrollView addConstraints:loginBtnHorizotal]; /*登录按钮垂直约束*/ NSArray *loginBtnViertical=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_portField]-30-[_loginBtn(==_portField)]-230-|" options:0 metrics:nil views:@{@"_loginBtn":_loginBtn,@"_portField":_portField}]; [self.scrollView addConstraints:loginBtnViertical]; } //连接Socket服务 -(void)connectAction:(UIButton *)sender{ NSLog(@"连接MQTT服务器登陆验证"); } @end