1.到底有多少种布局方式
关于iOS到底有多少种界面布局方式我一直都迷迷糊糊,今天仔细的来总结一下,以免别人问我的时候一脸懵逼。
界面布局主要分为两大类:手写代码和使用Interface Builder。
手写代码又分成两类:手写frame和手写constrains(autolayout)。
手写frame就是:
UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(8, 58, Width - 16, 1)];
这种方法做不同屏幕尺寸的适配非常麻烦。
手写constrains可以用苹果原生的语法去写(非常难写),也可以用框架Masonry去写,写起来方便许多。
使用Interface Builder又分成两大类:xib和storyboard。当然用ib也可以实现autolayout
使用storyboard添加约束或者属性的前提就是通过你设置的这些东西一定要能找到控件的大小和位置!
2.storyBoard多人开发问题
storyBoard在多人开发时容易出现冲突,在xcode7之前只要你打开了storyboard就算你啥也没干也会出现modify标签,在提交更新的时候就会出现conflict。
从Xcode 7以后,苹果针对这个问题推出了storyboard reference来解决storyboard的多人开发问题。可以把一个大的storyboard分解成多个小的模块,生成小的分开的storyboard文件,开发者只需要去修改自己负责的那个模块的storyboard文件就行了,不会引起冲突。
3.使用Masonry
Masonry其实就是一个比系统的autolayout用起来更加更加方便的实现自动布局的框架。
使用Masonry的注意事项:
1.要把子视图添加到父视图上以后才能添加约束,否则会崩溃。
2.要避免添加过多的约束,会造成约束冲突,也要避免添加的约束太少,太少的话可能没办法正确的显示控件的位置和大小,约束错误可以通过log日志查看。
哇!之前学习了关于更新UIView布局的几个方法,一起回顾一下。
layoutSubView 这个方法不会显示的调用,调用下面那两个方法的实质就是系统自动调用这个方法更新UI布局。
layoutIfNeeded 马上调用layoutSubView开始重新布局,前提条件是视图必须被setNeedsLayout方法标记过。⚠️:第一次更新布局的时候不需要标记setNeedsLayout方法,系统默认就标记了,之后更新布局的时候需要先手动标记setNeedsLayout方法,否则无法更新布局。
setNeedsLayout 不会马上调用layoutSubView重新布局,会把视图标记为需要更新布局,在下一个视图绘制周期也就是1/60s之后更新布局。
UIView不仅有更新视图布局的方法,还有更新约束布局的方法。
- (void)updateConstraints 重写此方法,内部实现自定义布局过程
- (void)updateConstraintsIfNeeded 调用此方法,如果有标记为需要重新布局的约束,则立即进行重新布局,内部会调用updateConstraints方法
- (void)setNeedsUpdateConstraints 标记需要进行重新布局
- (BOOL)needsUpdateConstraints 当前是否需要重新布局,内部会判断当前有没有被标记的约束
常用操作:
设置约束:
[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.view);// 这里通过mas_equalTo给size设置了基础数据类型的参数,参数为CGSize的结构体
make.size.mas_equalTo(CGSizeMake(300,300));}];
更新约束:⚠️:更新约束,写哪条更新哪条,其他约束不变
[self.greenView mas_updateConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(100, 100));}];
4.UIScrollView自动布局
给UIScrollView设置布局有两种思路,一种是提前知道了UIScrollView的contentSize,另外一种是在添加的过程中动态改变contentSize。
self.scrollView.contentSize =CGSizeMake(1000,1000);
[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view);}];
[self.scrollView addSubview:self.redView];
[self.redView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.top.equalTo(self.scrollView); make.width.height.mas_equalTo(200);}];
改变contentSize:UIScrollView原来的子视图都添加到containerView上,并且给这个视图设置约束。也就是containerView的父视图是contentView,通过containerView撑起contentView视图的大小,以此来实现动态改变contentSize。
self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view);}];
CGFloat padding = LXZViewPadding;
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.scrollView).insets(UIEdgeInsetsMake(padding, padding, padding, padding));}];
[self.containerView addSubview:self.greenView];
[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.left.equalTo(self.containerView).offset(padding); make.size.mas_equalTo(CGSizeMake(250,250));}];
5.屏幕适配
屏幕适配的几种常用方法:
1.代码直接计算
2.autoResizing 适合于控件和其父控件的关系
3.autoLayout 帮我们确定在不同设备、不同(父view)环境下,同一个可视单元所应具有合适的位置和尺寸(任何两个视图的关系都可以确定)
4.sizeClass 对当前所有iOS设备的一个抽象,把屏幕的宽和高分为三种类型:紧凑compact、宽松regular和任意any。
6.autoResizing
设置子视图根据父视图的frame的变化而变化,用autolayout适配完全可以替代这种方法,所以现在已经很少使用了。
1.用代码添加autoResizing属性,设置的方法是:
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|...;
⚠️这个属性添加的原则就是你添加谁,谁就是变的,然而造成这个属性的约束是不变的。
比如说设置UIViewAutoresizingFlexibleWidth,那就代表这个控件的宽改变,距离父控件的左右边距不变。
2.用interface builder添加autoresizing
先不要勾选Use Auto Layout和Use Size Classes
然后在倒数第二个那个地方去选择那个红色的线,选中谁就相当于添加了哪个属性,不选中就是不添加。
7.autolayout
autoresizing只能用来给子控件和他的父控件添加关联关系,但是autolayout可以给所有的控件添加关联关系。
核心就是参照和约束:参照:相对于谁,约束:距离谁有多少距离。
上面也说了可以使用纯代码Masonry,也可以用ib
8.sizeClass
sizeClass打破了以往屏幕种类的概念,没有什么横屏竖屏,只有宽高大小的概念。⚠️:iOS8之后出现。
把宽和高分成三类:compact压缩,regular宽松,any任意。
在给控件设置了autolayout之后可以选择width和height的sizeClass模式,3*3一共有9种模式可以选择。
参考:【SizeClass】SizeClass介绍