如何像WhatsApp一样禁用TableView且不遮挡全屏?(SearchController场景)
解决Xcode9.3+Swift4中SearchController仅暗化TableView的问题
我刚好在Xcode9.3+Swift4环境下处理过类似WhatsApp的搜索栏需求,默认的UISearchController确实会有全屏遮罩的问题,哪怕设置obscuresBackgroundDuringPresentation = false也没法直接实现只暗化TableView的效果。给你两个靠谱的解决方案:
方案一:自定义半透明遮罩(推荐,稳定可控)
这个方法完全不依赖系统私有逻辑,通过手动添加一个仅覆盖TableView的半透明视图,配合搜索栏文本变化来控制遮罩显示/隐藏以及TableView交互状态。
步骤与代码实现
- 定义变量:在你的ViewController中添加遮罩视图和SearchController的引用
import UIKit class YourViewController: UIViewController { @IBOutlet weak var tableView: UITableView! private var tableViewDimmingView: UIView! private let searchController = UISearchController(searchResultsController: nil) // ... 其他业务代码 }
- 初始化遮罩与配置SearchController:在
viewDidLoad中完成视图设置
override func viewDidLoad() { super.viewDidLoad() // 初始化半透明遮罩,仅覆盖TableView区域 tableViewDimmingView = UIView() tableViewDimmingView.backgroundColor = UIColor.black.withAlphaComponent(0.3) tableViewDimmingView.isHidden = true tableViewDimmingView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableViewDimmingView) // 用AutoLayout绑定遮罩到TableView的四个边缘,适配布局变化 NSLayoutConstraint.activate([ tableViewDimmingView.topAnchor.constraint(equalTo: tableView.topAnchor), tableViewDimmingView.leadingAnchor.constraint(equalTo: tableView.leadingAnchor), tableViewDimmingView.trailingAnchor.constraint(equalTo: tableView.trailingAnchor), tableViewDimmingView.bottomAnchor.constraint(equalTo: tableView.bottomAnchor) ]) // 配置SearchController,关闭默认全屏遮罩 searchController.searchResultsUpdater = self searchController.obscuresBackgroundDuringPresentation = false searchController.hidesNavigationBarDuringPresentation = false // 按需保留导航栏 navigationItem.searchController = searchController definesPresentationContext = true // 监听搜索栏文本变化事件 searchController.searchBar.addTarget(self, action: #selector(searchBarTextChanged(_:)), for: .editingChanged) }
- 实现文本变化与搜索更新逻辑:控制遮罩和TableView交互状态
@objc private func searchBarTextChanged(_ searchBar: UISearchBar) { updateDimmingViewState(isSearchEmpty: searchBar.text?.isEmpty ?? true) } extension YourViewController: UISearchResultsUpdating { func updateSearchResults(for searchController: UISearchController) { updateDimmingViewState(isSearchEmpty: searchController.searchBar.text?.isEmpty ?? true) } } // 封装状态更新逻辑,避免重复代码 private func updateDimmingViewState(isSearchEmpty: Bool) { tableViewDimmingView.isHidden = !isSearchEmpty tableView.isUserInteractionEnabled = !isSearchEmpty }
方案二:修改系统默认遮罩的Frame(适配性稍弱)
如果不想自定义遮罩,可以尝试找到UISearchController自带的背景遮罩视图,修改它的Frame使其仅覆盖TableView。不过这个方法依赖系统视图层级,不同iOS版本可能有变化,仅做备选参考。
代码实现
在viewDidAppear或SearchController的presentation回调中修改遮罩Frame:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 遍历SearchController的子视图,找到全屏背景遮罩 if let backgroundMask = searchController.view.subviews.first(where: { $0.backgroundColor != nil && $0.frame == view.bounds }) { // 将遮罩Frame改为TableView的范围 backgroundMask.frame = tableView.bounds backgroundMask.autoresizingMask = [.flexibleWidth, .flexibleHeight] } }
注意事项
- 方案一的AutoLayout绑定能更好适配屏幕旋转、TableView布局变化等场景,优先推荐。
- 如果你的TableView有导航栏或其他顶部视图,要确保遮罩不会覆盖这些区域,调整约束即可。
内容的提问来源于stack exchange,提问作者Oséias Ribeiro
相关产品推荐
相关产品推荐

