导入需要的图片资源
在开始修改UI之前,我们在项目文件列表里,选中Assets.xcassets文件夹,导入一些我们会使用的图片:

解决系统状态栏遮挡的问题
运行我们的App,不难发现,有一部分UITableView被系统的状态栏遮挡了,这是因为系统的状态栏实际上没有自己的UI位置,它会"浮"在任何App的UI上。

解决这个问题很简单,我们只要把视频列表嵌套在一个UINavigationController里就可以了。
在Document outline里,选中EpisodeListViewController,在菜单中选择"Edit" -> "Embed in" -> "Navigation Controller":

这样,Xcode就会把EpisodeListViewController嵌套在一个UINavigationController里了,这时,EpisodeListViewController的顶部就会出现一个新的空白区域,它叫做Navigation Bar,双击这个bar,我们先手动给它设置一个标题"Episode List":

如果我们要修改Navigation Bar的背景色和标题文字颜色,可以在Document outline中,选中"Navigation Bar":

然后在"Attribute inspector"中,设置"Bar Tint"和"Title color":

然后,Command + R编译执行,这样,EpisodeListViewController就不会被系统状态栏遮挡了。

改进视频列表UI
接下来,我们就把视频列表UI一步步改造成Sketch设计里的样子:。

自定义UITableViewCell对象
为了能在代码中更方便的访问我们自定义的UITableViewCell对象,我们先为自定义的Cell定义一个class。在项目列表中选中UITableViewDemo文件夹,按Command + N,选中"Swift file":

设置一个文件名"EpisodeListItemCell",点击"Create"按钮:

然后,我们创建一个UITableViewCell的派生类:
import UIKit
class EpisodeListItemCell: UITableViewCell {
}
设计UITableViewCell
回到Storyboard,在"Document outline"中,选中EpisodeItem,在"Identity inspector"中,把Class设置为EpisodeListItemCell。在"Attribute inspector中,把accessory type设置为"None":

保持EpisodeItem被选中,把Cell高度拉高一些:

从"Object library中拖一个UIImageView,并且,给它添加下图所示的约束:"

这样它就被固定在了Cell的顶端,用于显示视频的缩略图。保持UIImageView被选中,按Option + Command + =,让Xcode自动调整这个UIImageView的大小。
然后,我们给它的左上角,添加一个分类标签。在"Object library"里拖一个UILabel,并且在它的"Attribute inspector"里设置字体、字号、颜色、对齐方式和背景色;在"Size inspector"中,把尺寸设置为 90 x 30:

然后,我们给它添加下图中的约束:

对于Sketch中这个标签的圆角,稍后我们会在代码中进行设置,Storyboard暂时还无法完成这个工作。
然后,我们添加缩略图中间的播放图标。在Object library中拖一个UIImageView,尺寸设置成64x64,image设置为play-circle-64。
选中这个UIImageView,按住Ctrl把它拖拽到它"背后"的UIImageView上,在弹出的菜单以及"Pin"按钮上,设置下图的约束:

这样,整个视频预览图的部分,就设置完了。接下来,我们完成视频标题部分。我们先拖一个UIImageView进来,表示视频是否已经看过了;并用原来的UILabel表示视频的标题。
选中拖进来的UIImageView,设置它的尺寸(20x20)和图片(finished-green,这里的图标仅做示意,稍后我们会通过代码来设置它):

接下来,我们选中UILabel,设置它的属性:

Sketch中,已经看过的视频标题上的中划线,我们稍后会通过代码来设置。现在,我们要给UIImageView以及UILabel设置约束,当然分别给它们设置约束固然没问题,但是iOS 9为我们提供了一个更方便的工具:UIStackView。
UIStackView
在"Document outline"中,同时选中UIImageView和UILabel,在Storyboard右下角点击"Stack"图标:

这样,UIImageView和UILabel就变成一个整体了:

然后,我们解决图片被拉伸的问题。在"Document outline"中,选中"Stack View",在"attribute inspector"中,设置它的Alignment属性为"Center":

这样,图片的比例就恢复正常了,在我们继续之前,多说两句关于UIStackView的Alignment。
UIStackView的Axis和Alignment
根据我们把UI控件排列进UIStackView的方式,UIStackView定义了两个Axis:

其中水平排列的,叫做"Horizental",垂直排列的叫做"Vertical",这就是UIStackView的Axis。而无论是"Horizental"还是"Vertical",当排列进UIStackView的UI控件大小不同的时候,就要通过Alignment指定它们的对齐方式,当"Horizental"排列时,Alignment支持6种对齐方式:

而当UI控件按"Vertical"排列进UIStackView时,Alignment支持4种对齐方式:

这就是关于UIStackView的Axis和Alignment,理解了它的工作原理之后,就能明白为什么我们把视频标题的UIStackView的对齐方式设置为center之后,图标的尺寸就恢复正常了。
Content hugging & Content compression resistance
把视频标题中用到的UIImageView和UILabel合并为一个UIStackView之后,我们就可以把这个UIStackView作为一个整体,设置它的位置约束了。
在Document outline里,选中UIStackView,然后给它添加下面的约束:

这时,我们可以看到,虽然UIStackView占满了整个一行,但是,图标又被拉伸了,为了解决这个问题,我们需要了解一下auto layout里的两个概念:content hugging priority和content compression resistance priority。它们是UI控件的两个尺寸属性,我们可以在Size inspector中找到它们:

简单来说,content hugging priority表示了一个对象"拒绝变大"的强烈程度,值越高,就表示对象在水平或垂直方向拒绝变大的意愿越强烈;而content compression resistance则表示了一个对象"拒绝被压缩"的强烈程度,值越高,就表示对象在水平或垂直方向拒绝被压缩的意愿越强烈。
在视频标题的例子里,由于我们通过位置约束水平拉伸了UIStackView,导致了必然其中的UI控件尺寸会发生改变。调整的原则就是,UIStackView会选择content hugging priority低的(更容易妥协的)去改变,当所有UI控件的值相同时,UIStackView默认会拉伸第一个UI控件。
因此,为了保持视频标题左侧的图标不被拉伸,我们只要让它的conteng hugging priority更高,就可以了。
选中Stack view,我们先把它重新"拆"开。按住Option,点击Stack图标,选择"Unembed":

然后,我们重新把图标的尺寸设置为20x20,并且设置它的conteng hugging priority为255(任何大于251的值都可以):

然后,重新把UIImageView和UILabel变成一个UIStackView,设置Alignment为"Center",并给它添加和之前一样的位置约束,这一次,UILabel被拉伸了:

然后,我们保持UIStackView被选中,按Command + Option + +调整位置。在这里,为了我们之后可以方便找到这个Stack view,我们可以在Document Outline里,给它设置一个名字,例如:"Episode Title Stack":

UIStackView spacing
最后,如果我们要在UIStackView的UI控件之间设置一些距离,我们可以设置UIStackView spacing。选中"Episode Title Stack",把Spacing设置为8:

这样,视频标题我们就设置结束了。接下来,我们来设置视频的meta info,我们将继续了解UIStackView的更多用法。
UIStackView distribution
首先,我们拖一个UIImageView和UILabel,用来设置视频的更新时间:
UIImageView图片设置成last-updated,size设置成16x16:

UILabel设置成2016-04-11(这里的文字仅作为示意,我们稍后会通过代码修改它):

同样,我们把新加的UIImageView和UILabel转换成一个UIStackView,设置它的Alignment为center,spacing为6,并把这个UIStackView的名字设置为"Last updated":

然后,我们用同样的方式设置视频的总时长(duration)、难度(level)和经验值(exp):

这样,我们就有了4个新的UIStackView,为了能统一设置它们的位置,并且让它们在水平线上等距离分布,我们可以把这些UIStackView嵌套在一个新的UIStackView里。像上图一样选中它们,然后点击"Stack"图标:

这样,这4个UIStackView就被嵌套在了一个新的UIStackView里,我们管它叫做"Episode meta info"。然后,我们给它添加下面的位置约束:

这次,第一个子UIStackView中的图标又被拉伸了,原因我们之前已经讲过了。但由于我们并不是希望这4个UIStackView占满整行,而是希望它们以各自的大小水平等距分布,因此,我们只要设置Episode meta info的Distribution就可以了。
选中"Episode meta info",在attribute inspector中把Distribution设置为"Equal Spacing":

这样,它们就以自身实际大小,自动根据屏幕水平宽度等距分布了。然后,我们按Command + Optional + =,让Xcode自动调整位置。
最后,我们还要给EpisodeItem底部留出一些空白,用来显示视频的简介。