UISearchBar : How to prevent Cancel Button from clearing text?
Asked Answered
A

2

8

I have a screen with an UISearchBar within my app. It might be that there is already text in the searchbar, when the user enters the screen. If the user then taps into the field and then taps cancel, the content of the searchbar should not be cleared.

Is this achievable? I tried to implement searchBarCancelButtonClicked, but my modifications to the text property were ignored and the text field was still cleared.

Almaraz answered 13/2, 2014 at 18:44 Comment(6)
Did you set the delegate appropriately?Emanuele
Use UISearchBar without cancel buttonHewitt
@Guilherme: Yes, i am seeing a test log statement getting printed.Almaraz
@Akhilrajtr: And how is the user then supposed to cancel his operation (defocusing the searchbar).Almaraz
@Almaraz try setting custom selector to cancel button.Hewitt
How can i assign a custom selector for the cancel button? It does not seem obvious how to get a reference to this button.Almaraz
T
10

I ran in to this same problem and solved it by manually tracking the state of whether the cancel button was pressed. If it is, reset the text when the searchBar ends editing, as modifying searchBar.text in searchBarCancelButtonClicked doesn't work:

This is what I did in my UISearchBarDelegate class:

var searchTerms = ""
var searchWasCancelled = false

func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    searchWasCancelled = false
}

func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    searchWasCancelled = true
}

func searchBarTextDidEndEditing(searchBar: UISearchBar) {
    if searchWasCancelled {
        searchBar.text = self.searchTerms
    } else {
        searchTerms = searchBar.text
    }
}
Tensible answered 8/12, 2015 at 22:42 Comment(3)
I have a strange behaviour here. It almost works fine but if I type in something, then press the search button and afterwards cancel it, the searchBarTextDidEndEditing delegate method does never get called and the searchBar gets cleared.Reinforce
@Reinforce use method with _: func searchBarTextDidEndEditing(_ searchBar: UISearchBar)Ornithorhynchus
As written: "searchBarTextDidEndEditing delegate method does never get called".Reinforce
R
0

Bit of an update on this, as of iOS 15, it looks like changes in iOS 15 alter the order of which the searchBarCancelButtonClicked and searchBarTextDidEndEditing delegate methods are called.

Prior to iOS 15, a stateful solution such as the following would work for most use cases:


var searchTerms = ""
var searchWasCancelled = false

func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    searchWasCancelled = false
}

func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    searchWasCancelled = true
}

func searchBarTextDidEndEditing(searchBar: UISearchBar) {
    if searchWasCancelled {
        searchBar.text = self.searchTerms
    } else {
        searchTerms = searchBar.text
    }
}

Sadly, this breaks in iOS 15 and after some quick investigation, I can see that the searchBarTextDidEndEditing delegate method is always called prior to the searchBarCancelButtonClicked method. It’s unclear if this was an intended change by Apple or if it is indeed a bug.

All things aside, I've found a simple workaround to the original question and found that setting the searchBar.text from an async dispatch block, will successfully modify the text. Like so:

var previousSearchTerm = ""

func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    previousSearchTerm = searchBar.text ?? ""
}

func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    DispatchQueue.main.async {
        searchBar.text = self.previousSearchTerm
    }
}

Now this works for iOS 15 and prior, in my particular use case. However, depending what you're trying to achieve this may not be enough for backwards compatibility. It's also worth noting that this, like any other workaround modifying the stubborn default behaviour of UIKit, this comes with inherent risk of unknown side effects now or later on.

Rendon answered 6/10, 2021 at 6:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.