我花了一段时间才理解问题中的解决方案是什么意思,所以我认为澄清一下是个好主意。
需要为视图控制器创建一个实例变量。这需要存储从registerForPreviewing(with: sourceView:)
. 标准控制器显示时,必须作为方法 on 调用self
,但搜索控制器显示时,必须作为方法 on 调用(self.)searchController
。这就是@user8771003 提供的扩展的作用。UISearchController
也需要设置委托。
我为 a 创建了一些与 Swift 4.2、iOS 12 兼容的代码,UITableViewController
以使其更易于理解,尽管对于任何其他UIView
. 我已经使用self
来增加简洁性。
import UIKit
/// View controller for table view
class TableViewController: UITableViewController {
//
// MARK: - Properties
//
/// Data to display in table view
var data = [String]()
/// Controller for table view search bar
let searchController = UISearchController(searchResultsController: nil)
/// The 3D touch peek and pop preview context for switching between table view and search controller results
var previewingContext: UIViewControllerPreviewing?
//
// MARK: - Life cycle methods
//
/// Sets up the table view
override func viewDidLoad() {
super.viewDidLoad()
configureSearchBar()
setupPeekAndPop()
refreshData()
self.tableView.reloadData()
}
/// Configures behaviour for search bar on older devices
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if #available(iOS 11.0, *) {
} else {
self.searchController.dismiss(animated: false, completion: nil)
}
}
//
// MARK: - Table view data source
//
// ...
//
// MARK: - Navigation
//
// ...
//
// MARK: - Private methods
//
/// Reloads the data for the table view
/// - Parameter query: Search query to filter the data
private func refreshData(query: String = "") {
// ...
}
/// Configures the search bar
private func configureSearchBar() {
self.searchController.searchResultsUpdater = self
self.searchController.searchBar.placeholder = "Search"
self.searchController.delegate = self
if #available(iOS 11.0, *) {
self.searchController.obscuresBackgroundDuringPresentation = false
self.navigationItem.searchController = self.searchController
self.definesPresentationContext = true
} else {
self.searchController.dimsBackgroundDuringPresentation = false
self.searchController.hidesNavigationBarDuringPresentation = false
self.tableView.tableHeaderView = self.searchController.searchBar
}
}
}
// MARK: - Search results extension
/// Manages the extension for the `UISearchResultsUpdating` protocol to implement the search bar
extension TableViewController: UISearchResultsUpdating {
/// Updates the table view data when the search query is updated
func updateSearchResults(for searchController: UISearchController) {
let query = self.searchController.searchBar.text!
refreshData(query: query)
self.tableView.reloadData()
}
}
// MARK: - Peek and pop extension
/// Managess the extension for the `UIViewControllerPreviewingDelegate` protocol to implement peek and pop
extension TableViewController: UIViewControllerPreviewingDelegate {
//
// MARK: - Public methods
//
/// Manages the previwing of the destination view controller for peeking
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = self.tableView?.indexPathForRow(at: location) else { return nil }
guard let cell = self.tableView?.cellForRow(at: indexPath) else { return nil }
guard let detailVC = storyboard?.instantiateViewController(withIdentifier: "DestinationStoryboardIdentifier") as? DestinationViewController else { return nil }
let item = self.data[indexPath.row]
detailVC.item = item
detailVC.preferredContentSize = CGSize(width: 0.0, height: 0.0)
previewingContext.sourceRect = cell.frame
return detailVC
}
/// Manages the showing of the destionation view controller for popping
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
show(viewControllerToCommit, sender: self)
}
//
// MARK: - Private methods
//
/// Registers for peek and pop if device is 3D touch enabled
/// - Note: Should be called in `viewDidLoad()`
private func setupPeekAndPop() {
if traitCollection.forceTouchCapability == .available {
self.previewingContext = self.registerForPreviewing(with: self, sourceView: view)
}
}
}
// MARK: - Peek and pop on search results
/// Manages the extension for the `UISearchControllerDelegate` for implementing peek and pop on search results
extension TableViewController: UISearchControllerDelegate {
/// Switches previewing context for peek and pop to search controller results
func didPresentSearchController(_ searchController: UISearchController) {
if let context = self.previewingContext {
self.unregisterForPreviewing(withContext: context)
self.previewingContext = self.searchController.registerForPreviewing(with: self, sourceView: view)
}
}
/// Switches previewing context for peek and pop to table view
func didDismissSearchController(_ searchController: UISearchController) {
if let context = self.previewingContext {
self.searchController.unregisterForPreviewing(withContext: context)
self.previewingContext = self.registerForPreviewing(with: self, sourceView: view)
}
}
}