在iOS开发中,使用可视化编程能够简单快速的拖拽出令人满意的UI。但是,除了简单的拖拽之外,还有一项工作对于可视化编程来讲必不可少,那就是AutoLayout自适应布局。因为,没有进行AutoLayout的UI将无法适应屏幕大小不同的机型。本文主要基于Xcode 7.2.1总结一下个人在可视化编程中进行AutoLayout的几点经验,大神请绕过。
一、关于约束
在可视化编程中进行AutoLayout的方法就是添加约束。通过添加合适的约束,使控件能够按照预期的位置和大小显示在屏幕大小不同的机型上,也就实现了AutoLayout自适应布局。
1、添加约束
学习过可视化编程的小猿们应该都知道添加约束的几种主要方法:
方法一:使用 Interface Builder 界面右下角的 Stack 、Align 、Pin 、Resolve Auto Layout Issues 四个约束操作按钮。
方法二:在 Interface Builder 界面上,按住 control 键,从控件开始拖动鼠标到参考控件上,松开鼠标就会弹出约束选择窗口(如图 1-1)。
图 1-1
方法三:在 Interface Builder 界面左侧的 Document Outline 窗口中,按住 control 键,从控件开始拖动鼠标到参考控件上,松开鼠标就会弹出约束选择窗口(如图 1-2)。
图 1-2
2、约束分类
从上面的截图中我们可以发现,约束大致上可以分为三类:
2.1 距离约束
距离约束主要用于限定控件相对于参考控件的距离关系。相对于不同的参考控件,距离约束的具体名称会有一些区别,但作用效果基本相同。例如:
相对于根 View 的距离约束为:Leading Space to Container Margin 、Trailing Space to Container Margin 、Vertical Spacing to Top Layout Guide 、Vertical Spacing to Bottom Layout Guide 。
相对于非根 View 的父 View 的距离约束为:Top Space to Container 、Leading Space to Container 、Bottom Space to Container 、Trailing Space to Container 。
相对于无包含关系的其它控件的距离约束为:Horizontal Spacing 、Vertical Spacing 。
2.2 对齐约束
对齐约束主要用于限定控件相对于参考控件的距离关系。同样,相对于不同的参考控件,对齐约束的具体名称也会有一些区别。例如:
相对于跟 View 或父 View 的对齐约束为:Center Horizontally in Container 、Center Vertically in Container 。
相对于无包含关系的其它控件的对齐约束为:Center Horizontally 、Center Vertically 。
2.3 宽高约束
宽高约束主要用于限定控件相对于参考控件的宽高关系,包括:Equal Widths 、Equal Heights 、Aspect Ratio 。
二、窥探精髓
上面讲述了关于约束的基本内容,但具有可视化编程经验的小猿们都清楚,只知道这些基本内容还远不足以添加出能够满足各种 AutoLayout 需求的约束。所以说,接下来我们就深入其中,窥探精髓。
在 Interface Builder 界面中选中某个控件,我们就可以在 右侧 Utilities 窗口 —> Size 选项卡 —> Constraints 选项 下查看已经添加的约束(如图 2-1),并可以点击 Edit 或者双击进入约束详情对这些约束进行编辑。
图 2-1
或者我们可以直接在 Interface Builder 界面选中控件上的具体约束,在 右侧 Utilities 窗口 —> Size 选项卡 下就会显示约束详情(如图 2-2),可直接进行编辑。
图 2-2
约束详情中都包括哪些内容呢?下面我们就来详细了解一下。
在图 2-2 中我们可以看到,约束详情的最上面是约束的名称,也就是图中的 Center X Alignment Constraint ;最下面是一个 Placeholder 选项,内容是 Remove at build time ,从字面意思就可以知道,如果选择了这个选项,编译时将会移除这个约束,所以说一般情况下我们是不会勾选这个选项的;详情中剩余的内容也就是需要重点讲述的内容,其实这些内容都可以用 NSLayoutConstraint 的属性进行描述:
First Item:(id firstItem 属性).(NSLayoutAttribute firstAttribute 属性),其中的 firstAttribute 属性是可选的。
Relation:NSLayoutRelation relation 属性,有三个选项可供选择:Less Than or Equal(<=)、Equal(=)以及 Greater Than or Equal(>=),默认是 Equal(=)。
Second Item:(id secondItem 属性).(NSLayoutAttribute secondAttribute 属性),其中的 secondAttribute 属性是可选的。
Constant:CGFloat constant 属性,常数,可以手动输入,用以对约束进行调整。
Priority:UILayoutPriority priority 属性,优先级,默认值为1000,可以手动输入,一般不做修改。
Multiplier:CGFloat multiplier 属性,系数,可以手动输入,用以对约束进行调整。
Identifier:NSString *identifier 属性,约束标识。
这些内容遵循一个公式来限定约束:
First Item =(<=、>=) Multiplier × Second Item + Constant
这个公式就是约束的精髓,也就是可视化编程 AutoLayout 的精髓。公式中 First Item 的 firstAttribute 属性和 Second Item 的 secondAttribute 属性是可选的,Multiplier 系数和 Constant 常数可以手动输入,所以说我们可以通过编辑约束来随心所欲的修改约束,进而限定控件的位置和大小,实现可视化编程中的各种 AutoLayout 需求。
三、特殊需求
1、Label 的高度自适应
Label 的高度自适应非常简单。具有可视化编程经验的小猿们都知道,给 Label 加约束时不添加宽高约束也不会报错,因为系统默认 Label 的 numberOfLines = 1,height = 20.5,宽度根据文字长短自适应。但有些时候,我们需要使用 Label 显示一段很长的文本,就需要进行高度自适应:添加约束限定 Label 宽度,在 右侧 Utilities 窗口 —> Attributes 选项卡 —> Label 选项 下将 Lines 设置为0。
2、ScrollView 的 AutoLayout
曾经尝试过在可视化编程中对 ScrollView 进行 AutoLayout 的小猿们都知道,如果我们以 ScrollView 作为参考控件给其上的控件添加宽高约束,系统就会报错。怎么办呢?曾经有朋友告诉过我一个使用三方解决的方法,具体是什么三方我不记得了,因为我基本不会用这种方法。
那么我是怎么解决的呢?其实只要清楚问题的根源,我们就可以很简单的解决它。
我们使用代码创建 ScrollView 的时候,都必须要给定它的 contentSize 属性,但是我们在可视化编程时并没有对这一属性进行设置。所以,当我们以 ScrollView 作为参考控件给其上的控件添加宽高约束时,系统自然就会报错。解决问题办法也就是在给 ScrollView 上的控件添加宽高约束时以除 ScrollView 以外的其它控件作为参考控件。
考虑到我们可能会在 ScrollView 上添加很多个控件,最好的作法就是先在 ScrollView 上添加一个空白 View 作为 contentView ,添加好约束后将需要添加的控件添加到 contentView 上,这时就可以按照正常添加约束的方法给这些控件添加约束了。下面的动画演示的是在 ScrollView 上添加一个与根 View 等宽、高度为根 View 高度2倍的 contentView ,并添加约束的过程:
图 3-1
3、TableViewCell 的高度自适应
在实际开发中可能经常会遇到 Cell 的高度要根据显示的文字的多少进行调整的需求,这种情况下,如果我们通过可视化编程来定制 customCell ,又该怎样添加约束来使 customCell 的高度能够自适应呢?
首先,我们要给 customCell 中显示文字的 Label 添加约束:
第一步:限定 Label 的宽度,但不要限定 Label 的高度,因为 Label 高度自适应之后 customCell 才能高度自适应;
第二步:通过 Leading Space 或 Trailing Space 或 Center.X 限定 Label 在水平方向上的位置;
第三步:限定 Label 的 Top Space 和 Bottom Space 两个距离约束;
第四步:在 右侧 Utilities 窗口 —> Attributes 选项卡 —> Label 选项 下将 Lines 设置为0。
然后,我们要在代码中设置 TableView 的 estimatedRowHeight 和 rowHeight 属性:
self.tableView.estimatedRowHeight = 30 ; // 设置 customCell 的估计高度
self.tableView.rowHeight = UITableViewAutomaticDimension; // 设置 customCell 自适应高度
这样,我们就实现了 TableViewCell 的高度自适应。
四、实例演示
接下来根据实际开发中的一个 AutoLayout 需求,来给大家做一个小小的演示。之前一个朋友给提了一个 AutoLayout 的需求,具体的 UI 效果如图 4-1,要求三个 ImageView 等宽等高,之间的两个间隔和屏幕边缘的两个间隔宽度相等。朋友告诉我说他是在四个间隔区域使用了四个空白的占位 View ,然后再添加如下约束:
1、添加距离约束:限定两边的空白 View 与屏幕边缘的距离为0,限定四个占位 View 与三个 ImageView 两两之间的距离为0;
2、添加对齐约束:限定四个占位 View 和三个 ImageView 相对于根 View 竖直居中;
3、添加宽高约束:限定四个占位 View 和三个 ImageView 的高度均为 0.2 × 屏幕高度,限定四个占位 View 的宽度均为 0.07 × 屏幕宽度,限定三个 ImageView 的宽度均为 0.24 × 屏幕宽度。
图 4-1
如果试着把这些约束添加一遍,就会发现这种方法非常麻烦,还容易出错。但是,这篇文章读到这里,我们已经完全没必要再使用这种浪费空白占位 View 又非常麻烦的方法了。我们完全可以只对三个 ImageView 添加约束来实现图 4-1中的 UI 效果。计算 Multiplier 系数的过程请自行脑补,下面只演示添加约束的过程:
图 4-2