美文网首页2018技术笔记
2018笔记——Storyboard动态布局

2018笔记——Storyboard动态布局

作者: 满庭花醉三千客 | 来源:发表于2018-07-28 11:11 被阅读123次

之前一直用代码布局,新维护的项目是使用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.png

1的高度被改了,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

此时的效果就完美了~

加油!

相关文章

网友评论

    本文标题:2018笔记——Storyboard动态布局

    本文链接:https://www.haomeiwen.com/subject/wkqomftx.html