以动画的形式改变UITableViewCell的高度(Swift实现)

界面图

功能

看上面这张图片,整个界面是一个UITableView,其中有三个静态Cell。第二个Cell是一个通知开关。点击其右边的开关按钮,要求该Cell的底部能够动态地收起或展开。当打开开关时,要求时间控件展开;当关闭开关时,要求时间控件隐藏收起。

基础

我们都知道UITableViewDataSource有一个方法是tableView:heightForRowAtIndexPath:,通过这个方法,我们可以设定UITableView中某个Cell的具体高度。

同时,我们可以调用UITableViewreloadDatareloadRowsAtIndexPaths:withRowAnimation:方法来刷新整个界面的数据或者刷新某条数据。但是,一般使用这两个方法并不能很顺畅地刷新数据。

这里我们将用到另外两个方法:beginUpdatesendUpdates。这两个方法可以有效地以动画的形式执行刷新的工作。

实现

第一次用Swift实现的Demo

首先我们需要声明一个变量来控制展开或收起时间控件。可以直接利用开关的状态,这里简单的设置了一个布尔值来判断。

1
var shouldShowNotification = true

同时需要将时间控件关联到代码上,具体的关联方法可以查阅其他资料,这里就不赘述了。

1
@IBOutlet var datePicker: UIDatePicker!

然后实现UITableViewDataSource的方法

1
2
3
4
5
6
7
8
9
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 1 && self.shouldShowNotification
{
return 211
}
return 44
}

意思就是对应开关所在的Cell,如果需要展示,则返回 211 的高度,否则统一返回 44 的高度。

最后,将开关的事件绑定到代码里

1
2
3
4
5
6
7
8
9
10
11
12
@IBAction func notifyAction(sender: UISwitch) {
self.shouldShowNotification = sender.on
self.datePicker.hidden = !sender.on
// method 1
// self.tableView.reloadData()
// method 2
self.tableView.beginUpdates()
self.tableView.endUpdates()
}

对于 method 1,我们直接调用reloadData方法,这样的结果就是没有动画效果。

而对于 method 2,我们则调用了beginUpdatesendUpdates,可以看到该Cell变化时有十分流畅的动画效果。

注意

其实一开始在我原来的项目代码中直接使用beginUpdatesendUpdates,以及设置self.datePickerhidden的值并不能达到十分华丽的效果。因为Cell并没有直接把其区域外的视图截取。所以还需要多一步,就是把该CellClip Subviews置为YES,可以通过代码直接设置,或者直接在Interface Builder中设置。

后来发现XCode 7Interface Builder已经默认把这个选项勾选了。所以其实datePicker是否隐藏也不是很重要,只需要改变判断的布尔值,然后直接刷新就可以了。