如何解决UITableView滚动时SearchBar表头消失的问题?
解决UITableView滚动时SearchBar消失/上滚才显示的问题
嘿,我之前也碰到过一模一样的问题!你现在应该是把UISearchBar直接设置成tableView.tableHeaderView了,这种情况下,tableView向下滚动时,头部的搜索栏会跟着内容一起滑出屏幕,只有向上滚到顶部才会重新出现。如果这不是你想要的交互(或者你想让这个显示/隐藏的逻辑更流畅),试试下面几个方案:
方案一:用UISearchController整合到导航栏(最推荐)
这是苹果官方推荐的做法,能实现和系统App一致的搜索栏交互——滚动时自动隐藏,向上滚动时平滑显示,完全符合你的需求:
- 先创建并配置
UISearchController:
let searchController = UISearchController(searchResultsController: nil) // 如果你需要处理搜索相关的事件,记得设置代理 searchController.searchBar.delegate = self // 如果你想用Storyboard里拖好的searchBar,直接替换就行 searchController.searchBar = self.searchBar
- 在
viewDidLoad里把它绑定到导航栏:
override func viewDidLoad() { super.viewDidLoad() // 把搜索控制器加到导航项里 navigationItem.searchController = searchController // 这个属性控制滚动时是否隐藏搜索栏,设为true就是你要的“滚动消失、上滚显示”效果 navigationItem.hidesSearchBarWhenScrolling = true // 你的原有代码 conteudo = ["Augusto","Luis","Joao","Marina","Taina","Evandra","Miguel","Daniela","Luciano","Patricia","Jose","Vinicius","John"] tableView.dataSource = self }
这样设置后,完全不用自己写滚动逻辑,系统会帮你处理所有交互,体验非常顺滑。
方案二:让SearchBar固定在顶部(不随滚动消失)
如果你希望搜索栏一直留在顶部,不会跟着滚动消失,可以调整布局:
在Storyboard里修改结构:
- 把SearchBar从tableView的header里拖出来,直接放在ViewController的主View上。
- 给SearchBar添加约束:顶部、左、右都贴紧父View。
- 把tableView的顶部约束到SearchBar的底部,左、右、底部贴紧父View。
代码里不需要设置
tableView.tableHeaderView,保持原有数据源配置就好。
方案三:自定义滚动控制逻辑(适合特殊需求)
如果上面两种方案都不符合你的场景,必须用tableHeaderView来实现,那可以监听滚动事件手动控制显示:
- 先固定headerView的高度(避免自动调整导致的异常):
override func viewDidLoad() { super.viewDidLoad() // 设置searchBar为tableHeaderView tableView.tableHeaderView = searchBar // 关闭自动布局,手动固定高度 searchBar.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ searchBar.heightAnchor.constraint(equalToConstant: 44), // SearchBar默认高度 searchBar.widthAnchor.constraint(equalTo: tableView.widthAnchor) ]) // 原有代码 conteudo = ["Augusto","Luis","Joao","Marina","Taina","Evandra","Miguel","Daniela","Luciano","Patricia","Jose","Vinicius","John"] tableView.dataSource = self }
- 监听滚动事件,控制header的显示/隐藏:
// 记录上一次的滚动偏移量 var lastScrollOffsetY: CGFloat = 0 func scrollViewDidScroll(_ scrollView: UIScrollView) { let currentOffset = scrollView.contentOffset.y // 向下滚动且超过搜索栏高度时,隐藏header if currentOffset > lastScrollOffsetY && currentOffset > searchBar.frame.height { UIView.animate(withDuration: 0.3) { self.tableView.tableHeaderView?.frame.origin.y = -self.searchBar.frame.height } } // 向上滚动时,显示header else if currentOffset < lastScrollOffsetY { UIView.animate(withDuration: 0.3) { self.tableView.tableHeaderView?.frame.origin.y = 0 } } lastScrollOffsetY = currentOffset }
不过这种方式要注意边界情况(比如滚动到顶部时的复位),可能会有小bug,所以优先推荐方案一。
内容的提问来源于stack exchange,提问作者Augusto
相关产品推荐
相关产品推荐

