I have implemented 3D Touch with uicollectionview, it worked fine. But when the uisearchController is active, the 3D Touch doesn't work. The uisearchController uses the collectionView to show the results. same problem with the following post: 3d Peek & Pop for search results
Anyone has the same problem? Thanks
I have figured out the solution:
extension MyViewController: UISearchControllerDelegate {
func didPresentSearchController(_ searchController: UISearchController) {
if let context = previewingContext {
unregisterForPreviewing(withContext: context)
previewingContext = searchController.registerForPreviewing(with: self, sourceView: self.myCollectionView)
}
}
func didDismissSearchController(_ searchController: UISearchController) {
if let context = previewingContext {
searchController.unregisterForPreviewing(withContext: context)
previewingContext = registerForPreviewing(with: self, sourceView: self.myCollectionView)
}
}
}
It took me a while to understand what the solution in the question meant, so I thought that it would be a good idea to clarify it a bit.
An instance variable needs to be create for the view controller. This needs to store the previewing context returned from registerForPreviewing(with: sourceView:)
. When the standard controller is displayed, it must be called as a method on self
, but when the search controller is displayed, it must be called as a method on (self.)searchController
. That is what the extension provided by @user8771003 does. The delegate for the UISearchController
also needs to be set.
I created some Swift 4.2, iOS 12 compatible code for a UITableViewController
to make it easier to understand, although it will very similar for any other UIView
. I have made use of self
to increase brevity.
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)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With