I have implemented a UISearchBar to search through a catalogue of items from an external API. The Search functionality works as expected, however the problem is that every time I press the cancel button, which is on the right side of the search bar text field, the whole search bar moves down by one row and it looks like it pushes the entire table view down as well.
So if I type a letter into the search bar text field, then press cancel, the search bar text field moves down by 44px, which is the row height, and the table view itself also gets pushed down by the same amount. If i continuously press type something, then press cancel, the search bar will move further and further down the view. Any advice would be great! Here is my code:
import Foundation
import UIKit
import ItemLogger
private extension Selector {
static let dismiss = #selector(SearchVC.dismissView)
}
extension SearchVC: UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
}
extension SearchVC: UISearchBarDelegate {
func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
class SearchVC: UITableViewController {
let searchController = UISearchController(searchResultsController: nil)
var searchedItems = [ItemLog]()
var searchedImages = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
let leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "Back_Button"), style: UIBarButtonItemStyle.Plain, target: self, action: .dismiss)
self.navigationItem.leftBarButtonItem = leftBarButtonItem
}
override func viewWillAppear(animated: Bool) {
configureSearchController()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
func configureSearchController() {
guard !searchController.active else {
return
}
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Type to Search"
definesPresentationContext = true
searchController.searchBar.scopeButtonTitles = ["All"]
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
let view: UIView = self.searchController.searchBar.subviews[0] as UIView
for subView: UIView in view.subviews {
if let textView = subView as? UITextField {
textView.tintColor = UIColor.orangeColor()
textView.textColor = UIColor.blackColor()
textView.backgroundColor = UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.05)
}
}
searchController.searchBar.barTintColor = UIColor.whiteColor()
let cancelButtonAttributes: NSDictionary = [NSForegroundColorAttributeName: UIColor(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.33)]
UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes as? [String : AnyObject], forState: UIControlState.Normal)
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
tableView.reloadData()
}
override func tableView(tableView:UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.active && searchController.searchBar.text != "" {
return searchedItems.count
}
return 0
}
override func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("items", forIndexPath: indexPath)
let label = cell.viewWithTag(111) as! UILabel
let nameLabel = cell.viewWithTag(222) as! UILabel
let art = cell.viewWithTag(333) as! UIImageView
if searchController.active && searchController.searchBar.text != "" && searchController.searchBar.text != NSCharacterSet.whitespaceCharacterSet(){
label.text = searchedItems[indexPath.row].title
nameLabel.text = searchedItems[indexPath.row].name
art.image = searchedImages[indexPath.row]
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(searchedItems[indexPath.row])
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
if searchController.active && searchController.searchBar.text != "" && searchController.searchBar.text != NSCharacterSet.whitespaceCharacterSet() {
let queries: [SearchQueryOptions] = [
.QueryString(searchController.searchBar.text!)]
ItemLog.search(queries, completion: { (result) in
if let itms = result.response.result where itms.count > 0 {
self.searchedItems.removeAll()
self.searchedImages.removeAll()
for i in 0...itms.count - 1 {
self.searchedItems.append(itms[i])
self.searchedImages.append(itms[i].img)
}
}
self.tableView.reloadData()
})
}
}
func dismissView(){
self.navigationController?.popToRootViewControllerAnimated(true)
}
}
Try to call
configureSearchController()
inviewDidLoad
. And don't forget to callsuper.viewWillAppear(animated:)
in yourviewWillAppear
.Code tested in Swift 3.
Note: When, I, try your code. I was facing the same issue. Somehow, I managed to get around...
Updated:
Output from above code..hope, my answer will fix your problem....
I've made an open source project SearchTableView