Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

3D Touch doesn't work when searchController is active

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)
    }
}

}

like image 958
user8771003 Avatar asked Oct 23 '17 23:10

user8771003


1 Answers

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)
        }
    }

}
like image 130
Bilaal Rashid Avatar answered Nov 05 '22 20:11

Bilaal Rashid