UISearchBar disable auto disable of cancel button

2019-01-17 06:18发布

I have implemented a UISearchBar into a table view and almost everything is working except one small thing: When I enter text and then press the search button on the keyboard, the keyboard goes away, the search results are the only items shown in the table, the text stays in the UISearchBar, but the cancel button gets disabled.

I have been trying to get my list as close to the functionality of the Apple contacts app and when you press search in that app, it doesn't disable the cancel button.

When I looked in the UISearchBar header file, I noticed a flag for autoDisableCancelButton under the _searchBarFlags struct but it is private.

Is there something that I am missing when I setup the UISearchBar?

10条回答
成全新的幸福
2楼-- · 2019-01-17 06:24

For Monotouch or Xamarin iOS I have the following C# solution working for iOS 7 and iOS 8:

foreach(UIView view in searchBar.Subviews)
{
    foreach(var subview in view.Subviews)
    {
        //Console.WriteLine(subview.GetType());
        if(subview.GetType() == typeof(UIButton))
        {
            if(subview.RespondsToSelector(new Selector("setEnabled:")))
            {
                UIButton cancelButton = (UIButton)subview;
                cancelButton.Enabled = true;
                Console.WriteLine("enabledCancelButton");
                return;
            }
        }
    }
}

This answer is based on David Douglas solution.

查看更多
成全新的幸福
3楼-- · 2019-01-17 06:26

Here's my solution, which works for all situations in all versions of iOS.

IE, other solutions don't handle when the keyboard gets dismissed because the user dragged a scroll view.

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

// This will handle whenever the text field is resigned non-programatically
// (IE, because it's set to resign when the scroll view is dragged in your storyboard.)
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
    [self performSelector:@selector(enableCancelButton:) withObject:searchBar afterDelay:0.001];
}

// Also follow up every [searchBar resignFirstResponder];
// with [self enableCancelButton:searchBar];
查看更多
Viruses.
4楼-- · 2019-01-17 06:26

Here's a Swift 3 solution that makes use of extensions to get the cancel button easily:

extension UISearchBar {
    var cancelButton: UIButton? {
        for subView1 in subviews {
            for subView2 in subView1.subviews {
                if let cancelButton = subView2 as? UIButton {
                    return cancelButton
                }
            }
        }
        return nil
    }
}

Now for the usage:

class MyTableViewController : UITableViewController, UISearchBarDelegate {

    var searchBar = UISearchBar()

    func viewDidLoad() {
        super.viewDidLoad()
        searchBar.delegate = self
        tableView.tableHeaderView = searchBar
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        DispatchQueue.main.async {
            if let cancelButton = searchBar.cancelButton {
                cancelButton.isEnabled = true
                cancelButton.isUserInteractionEnabled = true
            }
        }
    }
}
查看更多
地球回转人心会变
5楼-- · 2019-01-17 06:27

As per my answer here, place this in your searchBar delegate:

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{   
    dispatch_async(dispatch_get_main_queue(), ^{
        __block __weak void (^weakEnsureCancelButtonRemainsEnabled)(UIView *);
        void (^ensureCancelButtonRemainsEnabled)(UIView *);
        weakEnsureCancelButtonRemainsEnabled = ensureCancelButtonRemainsEnabled = ^(UIView *view) {
            for (UIView *subview in view.subviews) {
                if ([subview isKindOfClass:[UIControl class]]) {
                    [(UIControl *)subview setEnabled:YES];
                }
                weakEnsureCancelButtonRemainsEnabled(subview);
            }
        };

        ensureCancelButtonRemainsEnabled(searchBar);
    });
}
查看更多
时光不老,我们不散
6楼-- · 2019-01-17 06:35

There is two way to achieve this easily

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
    //  The small and dirty
    [(UIButton*)[searchBar valueForKey:@"_cancelButton"] setEnabled:YES];

    // The long and safe
     UIButton *cancelButton = [searchBar valueForKey:@"_cancelButton"];
    if ([cancelButton respondsToSelector:@selector(setEnabled:)]) {
         cancelButton.enabled = YES;
    }
}

You should go with the second one, it will not crash your application if Apple will change it in the background.

BTW i tested it from iOS 4.0 to 8.2 and no changes, also i use it in my Store approved application without any issues.

查看更多
贪生不怕死
7楼-- · 2019-01-17 06:37

I found a solution. You can use this for-loop to loop over the subviews of the search bar and enable it when the search button is pressed on the keyboard.

for (UIView *possibleButton in searchBar.subviews)
{
    if ([possibleButton isKindOfClass:[UIButton class]])
    {
        UIButton *cancelButton = (UIButton*)possibleButton;
        cancelButton.enabled = YES;
        break;
    }
}
查看更多
登录 后发表回答