luke luke - 1 month ago 16
Swift Question

Constraints not changing when user cancels searching

So I have a search icon as my right bar button item. When the user taps the icon, it allows the user to search and only show certain values in the tableview. It also hides the nav bar buttons at the top and the

filterBar
just below the navigation controller

func setupNavBarButtons() {
let searchImage = UIImage(named: "search_icon")?.withRenderingMode(.alwaysOriginal)
let searchBarButtonItem = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(handleSearch))
navigationItem.rightBarButtonItem = searchBarButtonItem
setupFilterButton()
}


filter bar and navbar items to be hidden while searching like so:

func handleSearch() {
searchController.searchBar.isHidden = false
navigationItem.titleView = searchController.searchBar
searchController.searchBar.becomeFirstResponder()
navigationItem.rightBarButtonItems = nil
navigationItem.leftBarButtonItems = nil
filterBar.isHidden = true
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
}


And then it to reappear again once user stops searching, like so:

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
setupNavBarButtons()
searchController.searchBar.isHidden = true
filterBar.isHidden = false
tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
// Also tried tableView.topAnchor.constraint(equalTo: filterBar.bottomAnchor).isActive = true
}


Before Search:

enter image description here

During Search

enter image description here

After search: As you can see the tableview doesn't return to where it originally was. The
filterBar
is the gray view with 'Map' and 'Location'

enter image description here

Still got the same issue so I've uploaded my project here:

https://github.com/lukejones1/bug

Answer

At first, You added 'height' layout constraint with 40 px. and you added 'height' layout constraint with 0 px when user clicked search button. and again, you added 'height' layout constraint with 40 px when user clicked cancel button.

You need to reuse the layout constraint.

class ViewController: UIViewController {

var filterBarHeightLC : NSLayoutConstraint?

lazy var tableView : UITableView = {
    let tv = UITableView()
    tv.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
    tv.layoutMargins = UIEdgeInsets.zero
    tv.separatorInset = UIEdgeInsets.zero
    tv.backgroundColor = .red
    tv.translatesAutoresizingMaskIntoConstraints = false
    return tv
}()

lazy var filterBar : UIView = {
    let bar = UIView()
    bar.backgroundColor = .blue
    bar.translatesAutoresizingMaskIntoConstraints = false
    return bar
}()

fileprivate lazy var filterButton : UIButton = {
    let button = UIButton()
    button.setTitleColor(UIColor.white, for: UIControlState())
    button.setTitle("Filter", for: UIControlState())
    button.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left
    button.translatesAutoresizingMaskIntoConstraints = false
    return button
}()

fileprivate lazy var searchController: UISearchController = {
    let sc = UISearchController(searchResultsController:  nil)
    sc.dimsBackgroundDuringPresentation = false
    sc.hidesNavigationBarDuringPresentation = false
    sc.searchResultsUpdater = self
    sc.delegate = self
    sc.view.tintColor = UIColor.white
    sc.searchBar.tintColor = UIColor.white
    sc.searchBar.delegate = self
    return sc
}()

func setupNavBarButtons() {
    let searchBarButtonItem = UIBarButtonItem(title: "Search", style: .plain, target: self, action: #selector(handleSearch))
    navigationItem.rightBarButtonItem = searchBarButtonItem
    setupFilterButton()
}

func setupFilterButton() {
    let containerView = UIView()
    containerView.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
    containerView.addSubview(filterButton)
    filterButton.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
    filterButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
    let filterBarButtonItem = UIBarButtonItem(customView: containerView)
    navigationItem.leftBarButtonItem = filterBarButtonItem
}

override func viewDidLoad() {
    super.viewDidLoad()
    setupViews()
    setupNavBarButtons()
    view.backgroundColor = .white
}

func handleSearch() {
    searchController.searchBar.isHidden = false
    navigationItem.titleView = searchController.searchBar
    searchController.searchBar.becomeFirstResponder()
    navigationItem.rightBarButtonItems = nil
    navigationItem.leftBarButtonItems = nil

    // changed!
    filterBarHeightLC?.constant = 0
}

func setupViews() {
    view.addSubview(filterBar)
    view.addSubview(tableView)

    tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    tableView.topAnchor.constraint(equalTo: filterBar.bottomAnchor).isActive = true
    tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    filterBar.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    filterBar.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    filterBar.topAnchor.constraint(equalTo: view.topAnchor, constant: 64).isActive = true

    // changed!
    filterBarHeightLC = filterBar.heightAnchor.constraint(equalToConstant: 40)
    filterBarHeightLC?.isActive = true
}

extension ViewController: UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {

func filteredContentForSearchText(_ searchText: String, scope: String = "All") {
    tableView.reloadData()
}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    setupNavBarButtons()
    searchController.searchBar.isHidden = true

    // changed!
    filterBarHeightLC?.constant = 40
}

func updateSearchResults(for searchController: UISearchController) {
    filteredContentForSearchText(searchController.searchBar.text!)
}

}

Have a fun coding! :)

Comments