How do you keep the cancel button in the search bar enabled when the keyboard is dismissed?

孤街浪徒 提交于 2020-05-25 03:56:50

问题


enter image description hereenter image description here

I'm trying to achieve the same effect as Apple's Contacts app (left screenshot). The cancel button in UISearchBar is enabled even when the keyboard is dismissed. My app behaves differently (right screenshot). The cancel button automatically becomes disabled when the keyboard is dismissed. The user is forced to tap the cancel button one time to enable it and then another time to actually trigger the dismissal. This is not good user experience. How would I always keep the cancel button enabled like Apple's Contacts app?

Technical Details:

I'm not using UISearchDisplayController due to some design requirements. This is just a UISearchBar with my own custom search controller. The cancel button is shown using [self.searchBar showsCancelButton:YES animated:YES]. The keyboard is dismissed using [self.searchBar resignFirstResponder].


回答1:


Call to [self.searchBar resignFirstResponder] will make the cancel button disabled. Hence, you should always update cancel button to enable after calling it.

Objective-C

[searchBar resignFirstResponder];
UIButton *cancelButton = (UIButton *)[searchBar valueForKey:@"cancelButton"];
[cancelButton setEnabled:YES];

Swift

searchBar.resignFirstResponder()
if let cancelButton = searchBar.value(forKey: "cancelButton") as? UIButton
    cancelButton.isEnabled = true
}

In my experience, view.endEditing(true) is the problem. Because it's also called .resignFirstResponder if there's a UITextField inside the view, which is contained in UISearchBar.

https://developer.apple.com/reference/uikit/uiview/1619630-endediting




回答2:


For Swift 4.0

if let cancelButton : UIButton = searchBar.value(forKey: "cancelButton") as? UIButton{
    cancelButton.isEnabled = true
}



回答3:


You can use the runtime API to access the cancel button.

UIButton *btnCancel = [self.searchBar valueForKey:@"_cancelButton"];
[btnCancel setEnabled:YES];

As far as your question is concerned, there is no way you can enable the cancel button when the keyboard is dismissed, like there is no callback as such.




回答4:


Since iOS 7 all the subview of UISearchBar are one level deeper. This should work:

for (UIView *subView in searchBar.subviews) {
    for (UIView *secondLevelSubview in subView.subviews) {
        if ([view isKindOfClass:[UIButton class]]) {
           [(UIButton *)view setEnabled:YES];
        }
}

Still hacky and can easily break in the next iOS version.




回答5:


You could do this:

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    [self enableCancelButton];
}

- (void)enableCancelButton {
    for (UIView *view in _seachBar.subviews) {
        if ([view isKindOfClass:[UIButton class]]) {
            [(UIButton *)view setEnabled:YES];
        }
    }
}

BUT this is a pretty hackish method and I'm fairly certain it's generally frowned upon by Apple and could potentially lead to the app being rejected. As far as I know, there doesn't seem to be any other way to do what you're trying to do.




回答6:


Implement the below searchBarShouldEndEditing delegate method in your code. Hope it will helpful.

(BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar 
{
    [[searchBar valueForKey:@"_cancelButton"] setEnabled:YES];
    return YES;
}



回答7:


Here's a recursive solution that is working for me.

func enableButtons(_ view:UIView) { for subView in view.subviews { enableButtons(subView) } if let buttonView = view as? UIButton { buttonView.isEnabled = true } }




回答8:


Here's a simple way:

searchBar.resignFirstResponder()
(searchBar.value(forKey: "_cancelButton") as? UIButton)?.isEnabled = true



回答9:


Try this simple solution, works perfect for me

extension UISearchBar {

    func enableCancelButton(in view: UIView) {

        view.subviews.forEach {
            enableCancelButton(in: $0)
        }

        if let cancelButton = view as? UIButton {
            cancelButton.isEnabled = true
            cancelButton.isUserInteractionEnabled = true
        }
    }
}

extension ViewController: UISearchBarDelegate {

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        DispatchQueue.main.async {
            searchBar.enableCancelButton(in: searchBar)
        }
    }
}



回答10:


This is what worked for me to handle any dismissal such as searchBar.resignFirstResponder(), view.endEditing(false), interactive swipe to dismiss, presenting a view controller, etc.

extension ViewController: UISearchBarDelegate {

    func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
        //cancel button becomes disabled when search bar isn't first responder, force it back enabled
        DispatchQueue.main.async {
            if let cancelButton = searchBar.value(forKey: "cancelButton") as? UIButton {
                cancelButton.isEnabled = true
            }
        }
        return true
    }

}

Making sure to set searchBar.delegate = self.




回答11:


This Worked For me

// ViewdidLoad()
SearchBar.enableCancelButton(in: ParentViewOfSearchBar)


来源:https://stackoverflow.com/questions/24072069/how-do-you-keep-the-cancel-button-in-the-search-bar-enabled-when-the-keyboard-is

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!