Xcode 9.3 Swift:如何实现TableView分区表头高度变化的动画?
解决TableView表头搜索栏显示/隐藏的动画问题
嘿,我之前做项目时也踩过这个坑!直接修改表头高度后刷新的话,TableView不会自动给你加过渡动画,得用正确的方式触发它的布局更新逻辑。下面给你两种靠谱的实现方式,亲测在Xcode9.3+Swift环境下有效:
方法一:用TableView的beginUpdates() + endUpdates()(推荐)
这是最贴合TableView原生布局逻辑的方式,它会自动处理表头高度变化的平滑过渡动画:
- 先定义一个布尔变量控制搜索栏的显示状态:
var isSearchBarVisible = false { didSet { // 同步更新搜索栏的隐藏状态,避免高度变化后视图残留 tableView.headerView(forSection: 0)?.subviews.first(where: { $0 is UISearchBar })?.isHidden = !isSearchBarVisible } }
- 实现表头高度的代理方法,根据状态返回对应高度:
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { // 假设搜索栏放在第0分区的表头,其他分区高度保持默认 return section == 0 ? (isSearchBarVisible ? 44 : 0) : super.tableView(tableView, heightForHeaderInSection: section) }
- 导航栏按钮的点击事件里,切换状态并触发动画:
@IBAction func toggleSearchBarTapped(_ sender: UIBarButtonItem) { isSearchBarVisible.toggle() // 关键!用这两个方法包裹,TableView会自动生成高度变化的动画 tableView.beginUpdates() tableView.endUpdates() }
方法二:结合UIView动画手动调整表头frame
如果你需要更自定义的动画速度或曲线,可以用这种方式,不过相对麻烦一点:
@IBAction func toggleSearchBarTapped(_ sender: UIBarButtonItem) { isSearchBarVisible.toggle() guard let headerView = tableView.headerView(forSection: 0) else { return } UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut) { headerView.frame.size.height = self.isSearchBarVisible ? 44 : 0 // 强制TableView重新布局,确保动画生效 self.tableView.layoutIfNeeded() } // 同步隐藏/显示搜索栏 headerView.subviews.first(where: { $0 is UISearchBar })?.isHidden = !isSearchBarVisible }
避坑提醒
- 绝对不要直接调用
tableView.reloadData()或者tableView.reloadSections(_:),这些方法会强制刷新整个列表,直接打断动画效果。 - 如果你的表头视图是复用的(比如用了
dequeueReusableHeaderFooterView),记得在复用回调里同步更新搜索栏的隐藏状态和视图高度,避免布局错乱。
内容的提问来源于stack exchange,提问作者TakeYourMark
相关产品推荐
相关产品推荐

