Swift 4 - iOS 11 Search bar scope won't appear

2019-04-11 12:42发布

问题:

I have an app which works nice and without any problems on iOS 10 but with iOS 11 and Xcode Beta 5, I have this strange problem with search bar scope where the scope bar seems like it was cut from the bottom. (It was the same with all versions of Xcode beta and iOS 11) I would really really be glad if someone can put me in the right direction. Thanks

Above you can see what I see when I press the hamburger menu button. No problem here.. searchbar also has a scopebar which shows up when clicked on.I did not set it to show up programatically.But I guess this is its default behaviour when scope button titles are set.

The Problem:

When I click on the searchbar to enter information I see the screen above. On iOS 10 I had no problems. But now, with iOS 11, whatever I do I just cannot make it work like it works on iOS 10. Search scope bar shows up like it was cut from the bottom.

This is how it shows up in iOS 10 and I want it to be in iOS 11.

Storyboard view of the screen

I am pasting the relevant code here.

    class SlideMenuViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchControllerDelegate,UIGestureRecognizerDelegate{

     let searchController = UISearchController(searchResultsController: nil)

    @IBOutlet var sview: UIView!

    @IBOutlet var tableView: UITableView!



override func viewWillAppear(_ animated: Bool) {
//some non relevant code before this

 if sview.subviews .contains(searchController.searchBar) {
            print("Already contains")


        } else {

            sview.addSubview(searchController.searchBar)
            print(searchController.searchBar.showsScopeBar)

            searchController.searchBar.sizeToFit()
            searchController.searchBar.frame.size.width = view.frame.size.width



          searchController.searchBar.barTintColor = searchBarTintColor

            searchController.searchBar.tintColor = searchTintColor
        }



    }


override func viewDidLoad() {

//some other code

searchController.searchBar.delegate = self

searchController.searchBar.scopeButtonTitles = [NSLocalizedString("İsimlerde", comment: ""), NSLocalizedString("Açıklamalarda", comment: "")]

        searchController.searchBar.returnKeyType = UIReturnKeyType.done

searchController.searchResultsUpdater = self

        searchController.dimsBackgroundDuringPresentation = false
        definesPresentationContext = true

//some other code

}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

     if searchController.isActive && searchController.searchBar.text != "" {

        switch scpglobal {
            case NSLocalizedString("İsimlerde", comment: ""):
                return filteredIsimler.count

            case NSLocalizedString("Açıklamalarda", comment: ""):
                return filteredAciklamalar.count

            default:
                print("Tableview default")
        }

        }



        return isimlerArray.count
    }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

//some code about search here but nothing that will result in that behaviour

}

 func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        print("cancel")
        searchController.searchBar.text = ""

    }


func updateSearchResults(for searchController: UISearchController) {


        let searchBar = searchController.searchBar



        let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
        filterContentForSearchText(searchText: searchController.searchBar.text!, scope: scope)
        tableView.reloadData()
    }

}


extension SlideMenuViewController:UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        filterContentForSearchText(searchText: searchController.searchBar.text!, scope: searchController.searchBar.scopeButtonTitles![selectedScope])
    }
}

Edit: This is what happens if I add constraints to search bar. First everything seems good.

Then when you click on search bar this happens..Search bar moves out of the screen. See the arrow.

But if you close the sliding menu and re-open it then

Everything works OK until you click the cancel button. After that you have to do all this again to see the search bar working.

Code for the constraints

 searchController.searchBar.translatesAutoresizingMaskIntoConstraints = false
 sview.addConstraint(NSLayoutConstraint(item: searchController.searchBar, attribute: .top, relatedBy: .equal, toItem: sview, attribute: .top, multiplier: 1, constant: 0))
 sview.addConstraint(NSLayoutConstraint(item: searchController.searchBar, attribute: .bottom, relatedBy: .equal, toItem: sview, attribute:.bottom, multiplier: 1, constant: 0))

 sview.addConstraint(NSLayoutConstraint(item: searchController.searchBar, attribute: .leading, relatedBy: .equal, toItem: sview, attribute: .leading,multiplier: 1, constant: 0))
 sview.addConstraint(NSLayoutConstraint(item: searchController.searchBar, attribute: .trailing, relatedBy: .equal, toItem: sview, attribute: .trailing, multiplier: 1, constant: 0))

回答1:

Check out this WWDC 2017 video.

You should do something like this:

if #available(iOS 11.0, *) {
    navigationItem.searchController = searchController
    navigationItem.hidesSearchBarWhenScrolling = false
} else {
    tableView.tableHeaderView = searchController.searchBar
}

and then do the changes you need accordingly.



回答2:

I was able to resolve the issue by replacing searchController with a custom searchBar.

let searchBar = UISearchBar(frame:CGRect(x: 0, y: 0, width: 266, height: 100))

Be careful though, do not forget to use

searchBar.sizeToFit 

inside searchBarShouldBeginEditing and searchBarShouldEndEditing or else you might have strange UI problems especially if you are using the

searchBar.showsScopeBar = true

so, if you are having a similar problem, get rid of the searchController and implement a searchBar and its delegate methods. It will not give you the same scopeBar animation but at least it works. Another downside for this method is, if you have the searchBar.isTranslucent = true you might see the ghost of another scopeBar inside the searchBar. So make sure that

searchBar.isTranslucent = false

If anyone comes up with a better way to solve this problem, I am all ears...

Sample Delegate Setup

 func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
    searchBar.showsScopeBar = true
    searchBar.sizeToFit()
    searchBar.setShowsCancelButton(true, animated: true)
    return true
}

func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
    searchBar.showsScopeBar = false
    searchBar.sizeToFit()
    searchBar.setShowsCancelButton(false, animated: true)
    return true
}


回答3:

This might solve your problem:

func searchDisplayController(_ controller: UISearchController, willShowSearchResultsTableView tableView: UITableView)
 {
    tableView.backgroundColor = self.tableView.backgroundColor
    tableView.rowHeight = self.tableView.rowHeight
    tableView.tableFooterView = UIView()
}