iOS界面布局,代码还是IB?总有一款适合你

题图

Preface(废话)

iOS开发中一直有一个很具争议的话题,那就是界面布局到底是代码好还是使用IB(xib/storyboard)好?

有些人觉得手撸代码,才叫coder,使用代码的编译速度快(快不快苹果说了算)

有些人觉得IB的开发效率不容置疑,而且能减少界面代码对工程的污染

还有一些人觉得计算frame挺有意思…

好吧,如果还在使用initWithFrame()计算界面的布局,请在本文的留言区默默的扣个1...

本文不打算讨论哪个好,毕竟这么些年了,没有得出啥好的结论,代码的还是啪啪;IB也玩的很开心;

咱们把所有的方式都罗列一下,各位看官各取所需

手撸代码

Frame党

autolayout没有出来的时候,你使用frame也就不说啥了,因为在那个时候手机屏幕比较单一,就只有320*480一个,frame随便计算,但是现在这个时代那么多屏幕,你还是这个...

如果只是简单界面,你frame一下也没啥,请看下面的示例代码:

   // 分割线
    UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(8, 58, Width - 16, 1)];
    label1.backgroundColor = SEPARATORLINE;
    [self addSubview:label1];
    
    UILabel *label2 = [[UILabel alloc] initWithFrame:CGRectMake(8, 116, Width - 16, 1)];
    label2.backgroundColor = SEPARATORLINE;
    [self addSubview:label2];
    
    // 任务目标
    UILabel *aim = [[UILabel alloc] initWithFrame:CGRectMake(8, 8, 70, 21)];
    [self setLabel:aim WithTitle:@"任务目标:" withFont:FONT(15) withColor:PD_NAVI_COLOR];
    
    _taskAimLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 29, Width - 16, 21)];
    _taskAimLabel.font = FONT(13);
    [self addSubview:_taskAimLabel];
    
    // 任务奖励
    UILabel *award = [[UILabel alloc] initWithFrame:CGRectMake(8, 67, Width - 16, 21)];
    [self setLabel:award WithTitle:@"任务奖励:" withFont:FONT(15) withColor:PD_NAVI_COLOR];
    
    _taskAwardLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 88, Width - 16, 21)];
    _taskAwardLabel.font = FONT(13);
    [self addSubview:_taskAwardLabel];
    
    // 任务描述
    UILabel *des = [[UILabel alloc] initWithFrame:CGRectMake(8, 124, Width - 16, 21)];
    [self setLabel:des WithTitle:@"任务描述:" withFont:FONT(15) withColor:PD_NAVI_COLOR];
    
    _taskDescriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 145, Width - 16, 42)];
    _taskDescriptionLabel.font = FONT(13);
    _taskDescriptionLabel.numberOfLines = 2;
    [self addSubview:_taskDescriptionLabel];
    
    ... ...

我只想问,同学你真的不累么?你不累我这个维护者看着都累,如果是一个很长且布局不重复的界面,你咋办?

估计自己算着算着就晕了

所以,对于frame党,我只想说,你需要一个计算器...

手写Constraints

其实手写Constraints也是相当麻烦的,主要是因为Constraints有着非人的语法,给个例子大家随意感受一下

constraint = [  
    NSLayoutConstraint  
    constraintWithItem:testButton  
    attribute:NSLayoutAttributeCenterX  
    relatedBy:NSLayoutRelationEqual  
    toItem:self.view  
    attribute:NSLayoutAttributeCenterX  
    multiplier:1.0f  
    constant:00.0f  
];  

[self.view addConstraint:constraint];  

constraint = [  
    NSLayoutConstraint  
    constraintWithItem:testButton  
    attribute:NSLayoutAttributeBottom  
    relatedBy:NSLayoutRelationEqual  
    toItem:self.view  
    attribute:NSLayoutAttributeBottom  
    multiplier:1.0f  
    constant:-20.0f  
];  
  
[self.view addConstraint:constraint]; 

上面这段代码,只是添加了两个约束,试想一下,如果我们要写一个比较复杂的界面时,得写多长的代码?

不过,上面的代码可以优化

NSDictionary *viewsDic = NSDictionaryOfVariableBindings(deleteButton,cancelButton,nextButton);  
  
NSArray *constraints = nil;  
constraints = [NSLayoutConstraint constraintsWithVisualFormat:  
  @"H:|-25-[deleteButton(==cancelButton@700)]-(>=8)-[cancelButton(140)]-[nextButton(nextButtonWidth)]-rectY-|" 
               options:NSLayoutFormatAlignAllTop  
               metrics:@{@"rectY":@5,@"nextButtonWidth":@30}  
               views:viewsDic];  
[self.view addConstraints:constraints]; 

上面的代码看懂了么?

我自己都看不懂...

但是总有一些程序员和别的程序员不一样,他们能有不一样的能力,他们叫做大神,大神给我们封装了Masonry/Snapkit

Masonry/Snapkit

Masonry是一个轻量级的布局框架,拥有自己的描述语法,采用更优雅的链式语法封装自动布局,简洁明了,并具有高可读性,而且同时支持iOS和 Max OS X;SnapkitMasonryswift版本,语法也差不多

先看一个例子再说:

// masonry
[testButton mas_makeConstraints:^(MASConstraintMaker *make) {
    make.centerX.equalTo(self);
    make.size.mas_equalTo(CGSizeMake(50, 50));
    make.bottom.equalTo(hanupLabel.mas_top).offset(-10);
}];

// snapkit
testButton.snp_makeConstraints(closure: { make in
    make.centerX.equalTo(self);
    make.size.mas_equalTo(CGSizeMake(50, 50));
    make.bottom.equalTo(hanupLabel.mas_top).offset(-10);
})

控件直接调用mas_makeConstraints方法,在block中使用MASConstraintMaker进行相应的布局就行了,非常简洁

最重要的是可读性很高,在masonry里面有几点需要注意的地方:

  • 必须先把控件添加到父视图以后才能进行约束,不然会crash
  • mas_equalTo,在约束值为具体的数值(CGSize,CGPoint等也是)的时候需要使用这个
  • 内存管理,约束的block里面有时候会引起隐式内存泄露
  • 重复约束,或约束出现冲突的时候,在控制台会有log输出,发现以后改掉就好了
  • 如果多个约束在一行时,使用连接符语法(and),增强代码的可读性

上面几条是笔者在使用过程中总结的一些经验,大家可以参考一下,其实在这里内存管理方面,很值得说到;不过笔者在之前已经写过相关OC内存管理Swift内存管理的文章了大家可以出门左转进去看看,就能找到解决隐式内存泄露问题的办法

猜你喜欢

转载自blog.csdn.net/qq_41761551/article/details/81120218