Double tap necessary to select TableView item with Search Bar
Asked Answered
K

4

7

I have a UITableView with a search bar as header. I use this function to update my data when the user does a search in the search bar.

func updateSearchResults(for searchController: UISearchController) {

    if let searchText = searchController.searchBar.text {
        if (searchText.characters.count > 0) {
            self.filteredResults  = [];
            self.locationManager?.geocodeAddressString(addressString: searchText, completionHandler: { (results, error) in
                if error == nil && results != nil {
                    self.filteredResults = results!;
                    self.tableView.reloadData();
                }
            });
        }
        else {
            self.filteredResults  = [];
            self.tableView.reloadData();
        }
    }
}

and this function when I select a cell in my UITableView.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    self.delegate?.setCity(city: str);
    self.dismiss(animated: true, completion: nil);
}

Here is my problem : the view controller doesn't dismiss at the first taps on the cell. I taps once, the search bar resign responder. And I need to tap twice for the dismiss to execute.

Here is how I link my tableview and my search bar in viewDidLoad:

// Search Bar componants
self.searchController = UISearchController(searchResultsController: nil);
self.searchController.delegate = self;
self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = false;

self.searchBar = self.searchController.searchBar;
self.searchBar.searchBarStyle = .default;
self.searchBar.delegate = self;
self.searchBar.placeholder = NSLocalizedString("search.city", comment: "search.city").capitalized;

self.tableView = UITableView(frame: CGRect.zero, style: .plain);
self.tableView.translatesAutoresizingMaskIntoConstraints = false;
self.tableView.delegate = self;
self.tableView.backgroundColor = UIColor.white;
self.tableView.dataSource = self;
self.tableView.tableHeaderView = self.searchBar;
self.view.addSubview(self.tableView);

If someone could help me, that would be great :)

Kennethkennett answered 21/10, 2016 at 13:40 Comment(3)
Just a shot in the dark, if you switch the statements and dismiss the view first, does it work as expected?Seineetmarne
No. I really looks like the first taps just end the search bar editingKennethkennett
If you set a breakpoint in didSelectRowAt does the breakpoint get hit on the first tap?Seineetmarne
M
2

You can add a tap gesture recognizer to your view that when fired would

  1. resign the search bar responder
  2. convert the tap location to a point in you table view
  3. get the cell that tap location
  4. manually call didSelectRowAt which isn't the "best" solution but for demonstration purposes.

Here is how it looks implemented:

override func viewDidLoad() {
        super.viewDidLoad()

        // Add a tap gesture to our view
        let gesture = UITapGestureRecognizer(target: self, action: #selector(TestTableViewController.didTap(_:)))
        self.view.addGestureRecognizer(gesture)
    }

    // Called when the tap gesture fires
    func didTap(gesture: UITapGestureRecognizer) {

        // We get rid of our keyboard on screen
        searchBar.resignFirstResponder()

        // Find the location of the touch relative to the tableView
        let touch = gesture.locationInView(self.tableView)

        // Convert that touch point to an index path
        if let indexPath = tableView.indexPathForRowAtPoint(touch) {

            // Here I am just calling the delegate method directly which you shouldn't do.
            // You should just do whatever you want to do with the indexPath here.
            tableView(tableView, didSelectRowAtIndexPath: indexPath)
        }
    }
Multiphase answered 21/10, 2016 at 14:14 Comment(0)
Y
3

Swift 4+ or iOS 10+

1- Remove searching overlay on viewDidLoad or elsewhere.

searchController.obscuresBackgroundDuringPresentation = false

2- In TableView didSelectRowAt delegate add this line.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     searchController.isActive = false
     <your code>
}

..Done..

Note: with iOS 11+ if you use the SearchController in the navigation item, you will not have this problem. If you present the ViewController with the searchController, just add a new navigation with your ViewController. And present the new navigation instead.

UINavigationController(rootViewController: ViewControllerWithSearchBar) 
Yepez answered 30/3, 2020 at 9:44 Comment(0)
M
2

You can add a tap gesture recognizer to your view that when fired would

  1. resign the search bar responder
  2. convert the tap location to a point in you table view
  3. get the cell that tap location
  4. manually call didSelectRowAt which isn't the "best" solution but for demonstration purposes.

Here is how it looks implemented:

override func viewDidLoad() {
        super.viewDidLoad()

        // Add a tap gesture to our view
        let gesture = UITapGestureRecognizer(target: self, action: #selector(TestTableViewController.didTap(_:)))
        self.view.addGestureRecognizer(gesture)
    }

    // Called when the tap gesture fires
    func didTap(gesture: UITapGestureRecognizer) {

        // We get rid of our keyboard on screen
        searchBar.resignFirstResponder()

        // Find the location of the touch relative to the tableView
        let touch = gesture.locationInView(self.tableView)

        // Convert that touch point to an index path
        if let indexPath = tableView.indexPathForRowAtPoint(touch) {

            // Here I am just calling the delegate method directly which you shouldn't do.
            // You should just do whatever you want to do with the indexPath here.
            tableView(tableView, didSelectRowAtIndexPath: indexPath)
        }
    }
Multiphase answered 21/10, 2016 at 14:14 Comment(0)
G
0

Adding this to ViewDidLoad helped.

searchController.obscuresBackgroundDuringPresentation = false

https://developer.apple.com/documentation/uikit/uisearchcontroller/1618656-obscuresbackgroundduringpresenta says

"If you use the same view controller to display the searchable content and search results, it is recommended that you set this property to false. The default value of this property is true."

I used the same viewcontroller for searching and displaying. So, setting it to false helped me.

Grandiloquent answered 16/5, 2022 at 16:58 Comment(0)
U
0

I had the same issue. In my case the issue was how I dismissed my ViewController.

Instead of calling dismiss on the UIViewController

self.dismiss(animated: true, completion: nil)

Dismiss the UINavigationController instead to resolve the issue:

navigationController?.dismiss(animated: true, completion: nil)
Underdeveloped answered 5/12, 2023 at 12:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.