尽管现在已经是Apple将Storyboard整合进Xcode中的第四个年头,大家对于Storyboard的评价仍然褒贬不一。有早期就选择转向Storyboard用于UI开发的国内业界领头人物,也有创建项目就立马删除Storyboard的大牛。我经历过纯代码布局,同时也在多个多人合作项目中使用Storyboard开发界面。在初期绕过各种坑后,Storyboard将会是快速构建UI界面的好帮手,特别是在现如今设备分辨率与尺寸日益增加的情况下,它可以帮助工程师们节约大量的界面代码书写时间。Storyboard存在的一大意义在于为UI提供了可视化开发方式,另一方面提供了一种更好的MVC的View层实现方式,让你的ViewController代码更简洁。当然,Storyboard的不足仍然不可忽视,错误的难以定位经常让刚上手的开发者们手足无措,相比于代码更不容易阅读的XML源文件所导致多人合作中的冲突不易解决等问题仍然有待完善。本文从各个方面介绍一下Storyboard,分享一下Storyboard的一些使用心得。
历史
1986年Jean-Marie Hullot发明了IB(Interface Build–Storyboard的前身),并且和Macintosh的工具箱无缝融合,这一工具被Denison Bollay发现了。第二年, Denison Bollay带着Hullot和他的IB到NeXT,将IB演示给Steve Jobs看。老乔立意识到了IB的价值,并将其纳入到了NeXTSTEP中。之后Steve 带着NeXT的技术结晶(当然也包括IB)重新回归Apple,并将之整合到了Apple的体系中。2008年第一代iPhone SDK发布的时候,IB就已经捆绑在其中。到了Xcode4,Apple更是直接将其集成进IDE里。随后随着不断地改进,更新,演变,最终变成了我们今天所看到的Storyboard。从某种角度来说,Storyboard也是老乔留给我们的众多礼物之一。
故事板能做什么
故事板主要为我们提供了以下的功能:(这些功能都是可视化的)
- Auto Layout
- Size Classes
- Secnce的跳转
- 代码可视化
Auto Layout
自动布局颠覆了之前直接操作Frame的布局方式,从思考View应该在哪个位置,变成了考虑在特定条件下,View的所处的位置需要满足哪些条件。通过这些条件来确定View的Frame。自动布局在实际应用中大体上可以将分为三组:
View与Super View的约束
View自身的约束
View与Other View的约束
假如我们需要在代码中使用自动布局可以使用
Visual Format Language或者NSLayoutConstraint
的简单工厂方法来生成约束,然后添加到View上。我们来看一个例子:
1 | //用代码来实现上图中View与Super View的约束 |
是不是一大团乱糟糟的代码?Visual Format Language用起来更加令人崩溃。好在业界已经有比较好的代码自动布局的第三方解决方案。但是仍然会有大堆的简单界面布局代码残留在你的代码中。
为了让你的生活更轻松(也为了让代码更清爽),Storyboard就包含了非常优雅的可视化自动布局解决方案。以上一切,在Storyboard中都被浓缩成了两个按钮(下图红圈中的椭圆按钮)。
- 红框1:为被选中View和离他最近的View(可能是SuperView,也可能是另一个同层级的View,看哪个离它更近)添加Leading、Training、Top、Bottom四个属性约束。
- 红框2:为View添加自身宽和高约束
- 红色椭圆左侧按钮:当选中多个View时,为多个View添加约束
只需要点击几下鼠标,Storyboard就可以帮你轻松完成视图布局。
Auto Layout Debug
使用代码来对Auto Layout布局的另一个缺点在于debug的困难。当添加了多余的约束,往往只能在运行时才能发现错误。同时,要寻找出是哪一行代码添加了错误的约束也比较费力(往往连控制台都没有错误输出)。
而Storyboard却为此提供了非常友好的静态检查。主要针对View的约束、布局提供警告和Error,甚至是解决方案。
上图的例子是:我们为Label添加了多余的约束,Storyboard用红色标记出冲突的约束,并给出修改建议:删除其中一个约束以保证约束的正确性。是不是很友好? :)
Size Classes
Apple 与iOS 8推出了Size Classes的概念。意在解决因设备尺寸造成的适配问题。Size Classes通过将界面的宽度和高度抽象为正常
和紧凑
两种概念,通过合理的组合,可以将现有设备(以及未来将要出现的设备)划分到不同的Size中。因此,无论是代码还是界面布局,只需要针对Size进行,而不用再拘泥于分辨是iPhone还是iPad,是横屏还是竖屏的问题了。Size Classes的推出是具有前瞻性的,无论是Apple Watch还是iOS 9推出的的iPad 分屏模式,都可以用Size Classes完美解决适配的问题。
Size Classes和现有设备的对照表如下:
在之前,我们要对横屏竖屏的界面进行区分,代码一般是这样的:
1 | if (IPAD_PORTRAIT) |
在Size Classes时代,Apple引入了一个新的类UITraitCollection
来封装水平和垂直方向的Size信息。现在我们通过代码来改变界面是这样的:
1 | - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection |
在TODO中做相对应Size的事。
可以想见的是,仍然会有非常多的布局代码占据着你的源文件。但在Storyboard中,一切变得异常简单。
使用Size Classes,我们只需要选择相对应的size,在那个Size下进行布局。运行时,就会根据设备的尺寸,自动地展示相对应Size的布局。比如iPhone竖屏就展示width Compact height Regular
Size下的信息。当手机横屏,系统会自动添加一个过渡动画(虽然有点生硬),并转到width Regular height Compact
的Size。这一切不需要一行代码。
能不能再给力点?
Sure.有这么一种情景:iPhone横屏下,拥有一个avatarView
,竖屏下拥有一个相同的avatar View
。这种情况下我们只需要在一个Size中完成这个View,然后在Storyboard的attributed inspector
中做一些勾选,将其”install”进相对应的Size中,就可以达到复用的目的。如果有差异,则在对应的Size中定制即可。(如下图)
能不能再给力点儿?
Of Course!除了View,约束也可以不同Size配置不同。最厉害的是,图片文件也可以根据Size来区分。我们只需要对.xcassets
文件勾选Size Classes,就可以为不同Size配置不同图片.这意味着,在同一个安装包下,通过Size Classes,我们甚至可以为横屏iPhone和竖屏iPhone做出完全不同的App!