MikeG MikeG - 1 month ago 18
iOS Question

Search bar jumps down one row every time cancel button is tapped

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

}

Joe Joe
Answer

Code tested in Swift 3.

Note: When, I, try your code. I was facing the same issue. Somehow, I managed to get around...

class SearchVC: UITableViewController,UISearchResultUpdating {

var resultSearchController = UISearchController()

override func viewDidLoad() {
    super.viewDidLoad()

     configureSearchController()
 }


override var prefersStatusBarHidden: Bool {

    return true
}


func configureSearchController() {

    self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.dimsBackgroundDuringPresentation = false
        controller.hidesNavigationBarDuringPresentation = false
        controller.searchBar.searchBarStyle = .default
        controller.searchBar.sizeToFit()
        controller.searchBar.setShowsCancelButton(false, animated: true)
        controller.searchBar.keyboardAppearance = .default

        self.tableView.tableHeaderView = controller.searchBar

        //controller.searchBar.tintColor = UIColor(patternImage: UIImage(named: "xxxx")!)
        // controller.searchBar.setBackgroundImage(UIImage(named: "xxxx"), forBarPosition: UIBarPosition.Top, barMetrics: UIBarMetrics.Default)
        //  controller.searchBar.backgroundImage = UIImage(named: "xxxx")
        // controller.searchBar.setImage(UIImage(named: "search-icon.png"), forSearchBarIcon: UISearchBarIcon.Search, state: UIControlState.Normal)

        return controller
    })()


    for subView in self.resultSearchController.searchBar.subviews
    {
        for subsubView in subView.subviews
        {
            if let textField = subsubView as? UITextField
            {
                textField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search Text", comment: ""), attributes: [NSForegroundColorAttributeName: UIColor.red])

                textField.adjustsFontSizeToFitWidth = true
                textField.allowsEditingTextAttributes = true


                textField.textColor = UIColor.red
                textField.layer.borderColor = UIColor.gray.cgColor
                textField.layer.cornerRadius = 5
                textField.layer.masksToBounds = true

                textField.layer.borderWidth = 0.215

            }
         }  
      }
   }
}

Output from above code..hope, my answer will fix your problem.... enter image description here

Comments