之前一直用代码布局,新维护的项目是使用Storyboard写的,有一个需求:
美国站点的展示为名在前,然后中间名,姓在后。
香港/台湾站点的显示为姓在前,名在后,去除中间名。
涉及到一个控件的隐藏,两个控件的互换。
涉及到的地方有的是控件横向排列,有的是纵向排列。。
重新手写代码的概率是微乎其微的,因为给的时间只有3天,涉及到10个界面。
那就在Storyboard中修改了。
我写了一个测试代码来实现。
在Storyboard中添加控件,并加约束,实现如下效果:
屏幕快照 2018-04-19 上午11.10.04.png要动态显示,就要更新1,2,3控件顶部 距离父视图顶部的布局。a,b,c距离左侧/右侧距离俯视图左侧/右侧的距离。
我们先加约束,选中控件2,然后选择底部的|-□-|的按钮,然后选择距离顶部的距离,然后下拉一下,选择距离父视图的约束(默认是距离最近的一个视图)。然后选中这个约束,按control键,拖动到ViewController中,就会生成约束属性,我们可以修改该约束属性的constant即可。
屏幕快照 2018-04-18 下午4.48.34.png我们最终生成以下文件:
@property (weak, nonatomic) IBOutlet UILabel *oneView;
@property (weak, nonatomic) IBOutlet UILabel *twoView;
@property (weak, nonatomic) IBOutlet UILabel *threeView;
@property (weak, nonatomic) IBOutlet UILabel *aView;
@property (weak, nonatomic) IBOutlet UILabel *bView;
@property (weak, nonatomic) IBOutlet UILabel *cView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *oneTop;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *twoTop;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *threeTop;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *abWidth;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *acWidth;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *aLeading;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cTrailing;
然后我们在需要的地方修改值:
- (void)configureUI
{
//2隐藏掉,1移到下部,3移到顶部
self.twoView.hidden = YES;
self.oneTop.constant = 200;
self.threeTop.constant = 100;
//b隐藏掉,a移动到右侧,c移动到左侧
self.bView.hidden = YES;
CGFloat width = (self.view.frame.size.width-50)/2;
self.acWidth.constant = width;
self.aLeading.constant = width+20+10;
self.cTrailing.constant = width+20+10;
}
看一下效果:
Simulator Screen Shot - iPhone 6 Plus - 2018-04-19 at 11.21.53.png1的高度被改了,a不见了。。。
打印台出现这些信息:
屏幕快照 2018-04-19 上午11.23.07.png有约束冲突了,所以被改动了。
我们分析一下:
1的顶部距离父视图顶部为100 (Y:100 H:80)
2的顶部距离1底部为20(Y:100+80+20=200),距离父视图顶部为200(Y:200)
3的顶部距离2底部为20(Y:100+80+20+80+20=300),距离父视图顶部为300(Y:300)
修改后:
1的顶部距离父视图顶部为200 (Y:200 H:80)
2的顶部距离1底部为20(Y:200+80+20=300),距离父视图顶部为200(Y:200)
3的顶部距离2底部为20(Y:300+80+20=400 或 200+80+20 = 300),距离父视图顶部为100(Y:100)
可以看到,我们需要的是距离父视图顶部的那个约束,而不是优先使用距离最近的视图的约束。所以我们调整约束的优先级:1与2之间的间距约束、2与3的间距约束调整为900.默认为1000,即强制约束,最低为1,数值越大,发生约束冲突时,优先取高优先级的进行布局。
屏幕快照 2018-04-19 下午1.59.31.png看一下效果:
屏幕快照 2018-04-19 下午2.00.35.png此时1和3都没问题了。
同理,我们分析一下abc视图(略去Y位置,因为都一样,且UI更新前后,未改动)
元素宽度W=(PhoneW-20-10-10-20)/3
A视图的左侧距离父视图左侧为20,右侧距离B视图左侧为10,与BC等宽为W
B视图的左侧距离A视图的右侧为10,右侧距离C视图的左侧为10,与AC等宽为W
C视图的左侧距离B视图的右侧为10,右侧距离父视图右侧10,与AB等宽为W
初始状态为:
A的X为20
B的X为20+W+10
C的X为20+W+10+W+10
修改后:
元素宽度W=(PhoneW-20-10-20)/2
A视图的左侧距离父视图左侧为20+10+W,右侧距离B视图左侧为10,与C等宽为W
B视图的左侧距离A视图的右侧为10,右侧距离C视图的左侧为10,与AC等宽为W
C视图的左侧距离B视图的右侧为10,右侧距离父视图右侧为10+W+20,与A等宽为W
如果满足A的leading:10+20+W ,则B的X:10+20+W+W+10(A右侧+10),那么C的X:10+20+W+W+10+W+10(B右侧+10)
如果满足C的trailing:10+W+20,则B的X:10+W+20-W-10(C视图的左侧-10),那么A的X:10+W+20-W-10-W-10(B视图的左侧-10)
两套算出来的结果是完全不一样的。
分析:这里的X布局与Y布局不一样,Y布局不会影响高度,X布局会影响宽度,原先一行放置3个控件,现在为2个。
解决方案(3个控件时的布局):
元素宽度W=(PhoneW-20-10-10-20)/3
A控件布局约束:
左侧:距离父视图为aLeading
右侧:距离B视图左侧为10,优先级为900
右侧:距离父视图右侧为10+W+10+W+20,优先级1000
Width:移除约束
Top:不变
B控件布局约束:
左侧:距离A视图右侧为10,优先级900
右侧:距离C视图左侧为10,优先级900
Width:移除约束
Top:不变
C控件布局约束:
左侧:距离父视图左侧为10+W+10+W+20,优先级1000
左侧:距离B视图的右侧为10,优先级900
右侧:距离父视图右侧为20
Width:移除约束
Top:不变
解决方案(2个控件时的布局):
元素宽度W=(PhoneW-20-10-20)/2
A控件布局约束:
左侧:距离父视图为20+W+10
右侧:距离B视图左侧为10,优先级为900(实际布局时未采用该约束,因为优先级较低)
右侧:距离父视图右侧为20,优先级1000
Width:移除约束
Top:不变
B控件布局约束:(不改动,因为已经隐藏了)
左侧:距离A视图右侧为10,优先级900
右侧:距离C视图左侧为10,优先级900
Width:移除约束
Top:不变
C控件布局约束:
左侧:距离父视图左侧为20,优先级1000
左侧:距离B视图的右侧为10,优先级900(实际布局时未采用该约束,因为优先级较低)
右侧:距离父视图右侧为10+W+20
Width:移除约束
Top:不变
实际编码:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
NSString *state = [[NSUserDefaults standardUserDefaults]objectForKey:@"currentState"];
if ([state isEqualToString:@"1"]) {
//3个控件,abc的布局
CGFloat width = (self.view.frame.size.width-60)/3;
self.aLeading.constant = 20;
self.aTrailing.constant = 10+width+10+width+20;
self.cTrailing.constant = 20;
self.cLeading.constant = 10+width+10+width+20;
}else if ([state isEqualToString:@"2"]){
[self configureUI];
}
}
//2个控件
- (void)configureUI
{
//2隐藏掉,1移到下部,3移到顶部
self.twoView.hidden = YES;
self.oneTop.constant = 200;
self.threeTop.constant = 100;
//b隐藏掉,a移动到右侧,c移动到左侧,ac的布局
self.bView.hidden = YES;
CGFloat width = (self.view.frame.size.width-50)/2;
self.aLeading.constant = width+20+10;
self.aTrailing.constant = 20;
self.cTrailing.constant = width+20+10;
self.cLeading.constant = 20;
}
效果:
Simulator Screen Shot - iPhone 6 Plus - 2018-04-19 at 15.25.35.png此时的效果就完美了~
加油!
网友评论