今天我们讲到了UIViewController,然后就提到了一个横屏和竖屏的时候视图变化问题,刚开始我们学的是一个比较传统的方法,通过判断屏幕当前的状态然后在对view进行重新的调整。在学习的过程中,翔哥又给我们提到了一种新的方法VFL,并且用代码简单的实现了一下,然而并不是很懂。。。然后就自己在网上找了多篇对VFL的使用,不过都不是很明了。然后就自己就总结实践了一下,下面说一下我自己的使用方法。
1.先创建两个类,LoginViewController和LoginView,父类分别是UIViewController和UIView。然后将LoginView挂到LoginViewController上。然后再LoginView中添加两个UILabel属性
2.当屏幕旋转的时候视图控制器会向他下面的LoginView发送一个消息,让视图进行重新布局。
3.在LoginView中对View重新布局
- (void)layoutSubviews
{
[self addConstraints:(NSArray *)];
}
从上面的布局方法中可以看到addConstraints:(NSArray *)需要一个NSArray类型的参数。而下面的方法返回类型正好是NSArray。所以就必须先了解下面的方法:
NSLayoutConstraint经常使用的一个方法
+ (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;
参数介绍:
format:字符串类型的。主要是用来约束屏幕在横竖的时候控件或view的位置尺寸的
opts:默认参数,默认写0;具体根据自己想实现的要求去选择枚举值
metrics:是一个字典,里面主要写一些format字符串中要使用到的参数。系统会自动的将format字符串中的参数 在metrics字典中查找和参数名相同的key值,然后使用key值对应得value值。如果,你使用metrics这个字典了,就必须保证format字符串能在里面找到这个key值,否则会报错。
views:又是一个字典。这里面是VFL中所有使用到的view。
对format字符串中的格式做一个了解
功能 表达式
水平方向 H:
垂直方向 V:
Views [view]
SuperView |
关系 >=,==,<=
空间,间隙 -
优先级 @value
代码实现:
在LoginView中添加两个UILabel属性,记得释放哦
#import
@interface LoginView : UIView
@property (nonatomic , retain) UILabel *firstLabel;
@property (nonatomic , retain) UILabel *secLabel;
@end
在LoginView.m中进行实现:
第一种情况:
1.LoginView中只添加一个控件的时候,我们将firstLabel添加上去
// 布局视图
- (void)addSubviews
{
// 设置背景颜色
self.backgroundColor = [UIColor cyanColor];
// 添加firstLabel
self.firstLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 30)];
self.firstLabel.layer.borderWidth = 1;
self.firstLabel.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.firstLabel.layer.cornerRadius = 5;
self.firstLabel.text = @"点我";
self.firstLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.firstLabel];
[self.firstLabel release];
}
#pragma mark - 屏幕旋转方法的实现
- (void)layoutSubviews
{
UILabel *fl = self.firstLabel;
fl.translatesAutoresizingMaskIntoConstraints = NO;// 这个必须写否则下面的约束方法不起作用
//firstLabel控件约束
// 水平方向上的约束
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[fl]-50-|" options:0 metrics:nil views:@{@"fl":fl}]];
//垂直方向上的约束
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[fl(==30)]" options:0 metrics:nil views:@{@"fl":fl}]];
}
对约束方法解析:
@"H:|-50-[fl]-50-|"其中"H:"是表示这是水平方向上的约束,"|"是表示superView,"-"表示一个间隔空间,这个间隔如果是和superView之间的,那么就是20px,如果是两个同级别的view,比如@"[label]-[label1]",那么这里表示的是8px.
@"V:|-100-[fl(==30)]"其中"V:"中代表这是垂直方向上的约束,"|-100-"这里的意思就是距离头部为100px,相当于y坐标为100。后面的"[fl(==30)]",是指定这个label的高度为30px.y坐标固定了,高度固定了,那这个view的约束就完成了。如果你有需要,你的高度值(或者其他同类型的)可以使用>=,==,<=来表示,甚至你可以组合来用,像上面的30
运行结果对比:
2.LoginView中有2个控件,也可以由多个控件,上代码:
// 布局视图
- (void)addSubviews
{
// 设置背景颜色
self.backgroundColor = [UIColor cyanColor];
// 添加firstLabel
self.firstLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 30)];
self.firstLabel.layer.borderWidth = 1;
self.firstLabel.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.firstLabel.layer.cornerRadius = 5;
self.firstLabel.text = @"点我";
self.firstLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.firstLabel];
[self.firstLabel release];
// 添加secLabel
self.secLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 150, 200, 30)];
self.secLabel.layer.borderWidth = 1;
self.secLabel.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.secLabel.layer.cornerRadius = 5;
self.secLabel.text = @"使劲点";
self.secLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.secLabel ];
[self.secLabel release];
}
#pragma mark - 屏幕旋转方法的实现
- (void)layoutSubviews
{
// 拿到两个控件
UILabel *fl = self.firstLabel;
UILabel *sl = self.secLabel;
fl.translatesAutoresizingMaskIntoConstraints = NO;// 这个必须写否则下面的约束方法不起作用
sl.translatesAutoresizingMaskIntoConstraints = NO;
// metrics参数 和 views参数
NSDictionary *metrics = @{@"Height":@30 , @"Width":@200};
NSDictionary *views = NSDictionaryOfVariableBindings(fl,sl);
//firstLabel控件约束
// 水平方向上的约束
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[fl]-50-|" options:0 metrics:metrics views:views]];
//垂直方向上的约束
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[fl(==Height)]" options:0 metrics:metrics views:views]];
// secLabel约束
// 水平约束
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-50-[sl(==fl)]" options:0 metrics:metrics views:views]];
// 垂直约束
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[fl]-30-[sl(==fl)]" options:0 metrics:metrics views:views]];
}
当两个控件时,我们可以像添加第一个控件时把第二个控件添加上去;同时也可以把第一个控件作为参照添加第二个控件,上面的方法就是把第一个控件作为参照,对控件重新布局;
首先看一下这个俩个参数:
// metrics参数 和 views参数
NSDictionary *metrics = @{@"Height":@30 , @"Width":@200};
NSDictionary *views = NSDictionaryOfVariableBindings(fl,sl);
metrics中的参数在VFL中有用到,就是format
views主要用在多控件的时候;
通过下面的水平和垂直设置实现:第二个控件和第一个控件等高同宽(如下);也可以自己定义宽度和高度
@"H:|-50-[sl(==fl)]"
@"V:[fl]-30-[sl(==fl)]"
运行结果对比:
(竖屏)
(横屏)