2

I have a textField on the top of my view and a tableView which should be placed below the textField.

So my code for adding them looks like:

private func setupSearchBar() {
    searchtextField = UITextField()
    mapView.addSubview(searchtextField)
    searchtextField.translatesAutoresizingMaskIntoConstraints = false

    let constraints = [
        NSLayoutConstraint(item: searchtextField, attribute: .leading, relatedBy: .equal, toItem: mapView.safeAreaLayoutGuide, attribute: .leading, multiplier: 1.0, constant: 16.0),
        NSLayoutConstraint(item: searchtextField, attribute: .trailing, relatedBy: .equal, toItem: mapView.safeAreaLayoutGuide, attribute: .trailing, multiplier: 1.0, constant: -16.0),
        NSLayoutConstraint(item: searchtextField, attribute: .top, relatedBy: .equal, toItem: mapView.safeAreaLayoutGuide, attribute: .top, multiplier: 1.0, constant: 24.0),
        NSLayoutConstraint(item: searchtextField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 46.0)
        ]

    NSLayoutConstraint.activate(constraints)
}

after this I'm setting up my tableView:

private func setupResultsTableView() {
    tableView = UITableView()
    mapView.addSubview(tableView)
    tableView.translatesAutoresizingMaskIntoConstraints = false

    tableViewHeightAnchor = tableView.heightAnchor.constraint(equalToConstant: 0)
    let constraints = [
        tableView.safeAreaLayoutGuide.topAnchor.constraint(equalTo: searchtextField.safeAreaLayoutGuide.bottomAnchor),
        tableView.safeAreaLayoutGuide.leadingAnchor.constraint(equalTo: mapView.safeAreaLayoutGuide.leadingAnchor),
        tableView.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: mapView.trailingAnchor),
        tableViewHeightAnchor!,
        tableView.safeAreaLayoutGuide.bottomAnchor.constraint(lessThanOrEqualToSystemSpacingBelow: view.safeAreaLayoutGuide.bottomAnchor, multiplier: 1.0)
    ]
    NSLayoutConstraint.activate(constraints)
}

What I want to do is: 1. To set the tableView height to 0 2. When user starts to type in my textField, according to the search results to display tablView and set its height to the contentSize of the tableView. So the maximum size will be sticked to the bottom of the device and if there are 1-2 results displayed, then to make the tableView smaller.

When user starts to type, I run the next:

func textFieldDidBeginEditing(_ textField: UITextField) {        
    filterContentForSearchText(textField.text!)
    tableView.reloadData()

    UIView.animate(withDuration: 0.6) {
        self.tableView.layoutIfNeeded()

        if textField.isEditing {
            self.tableViewHeightAnchor.constant = self.tableView.contentSize.height
        } else {
            self.tableViewHeightAnchor.constant = 0.0
        }
    }
}

But something wrong in my code, because I get such ugly results: When I start to swipe up, the tableView starts to go up and goes over my textField

enter image description here

and when I finish scrolling it stops in the middle of the view enter image description here

Is there a way to fix that problem? If you have any question, please ask me

J. Doe
  • 521
  • 4
  • 15

1 Answers1

1

Lets set tableView full height and toggle its visibility, like so:

tableView.backgroundColor = .clear
tableView.isHidden = true
tableView.tableFooterView = UIView()

With these constraints for tableView:

NSLayoutConstraint.activate([
    tableView.topAnchor.constraint(equalTo: searchtextField.bottomAnchor),
    tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
    tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
    tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, multiplier: 1.0)
])

Now we can use UITextFieldDelegate methods to toggle our tableView:

func textFieldDidBeginEditing(_ textField: UITextField) {
    self.toggleSearch(true)
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

func textFieldDidEndEditing(_ textField: UITextField) {
    self.toggleSearch(false)
}

private func toggleSearch(_ value: Bool) {
    self.tableView.isHidden = !value
}

Don't forget to set searchtextField.delegate = self

Additionally, you can add a semi transparent backgroundView and use this animated version of toggleSearch to fade in/out tableView:

let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
backgroundView.layer.opacity = 0
tableView.backgroundView = backgroundView

private func toggleSearch(_ value: Bool) {
    var completionBlock: ((Bool) -> Void)?
    if (value) {
        self.tableView.isHidden = false
    } else {
        completionBlock = { [weak self] _ in self?.tableView.isHidden = true }
    }

    UIView.animate(withDuration: 0.3, animations: {
        self.tableView.backgroundView?.layer.opacity = value ? 1 : 0
    }, completion: completionBlock)
}
AamirR
  • 11,672
  • 4
  • 59
  • 73
  • thank you very much! It helped me a lot but I have some issue, when my tableView has only ONE row — I cannot select it, but it's possible when there are few of them, for example 2+. Can you tell me what the problem is or what can it be? – J. Doe Sep 27 '18 at 08:38
  • **cannot select it** you mean `tableView(_ tableView: UITableView, didSelectRowAt indexPath` is not called? may be a view covering top of your tableView, or something with the cell, try running in simulator and see in `Debug View Hierarchy` or this https://teamtreehouse.com/community/ios-bug-cant-access-the-first-cell-in-tableview or this https://stackoverflow.com/a/33226911/1244597 can't be sure, if nothing helps, create a gist of the .swift file and share the link – AamirR Sep 27 '18 at 09:33