简体   繁体   中英

Perform action on UISearchBar when Keyboard is down and the x has been tapped

I have a UITableView with a UISearchBar on top and have a specific requirement that isn't working.

I have no Cancel button on my UISearchBar (showsCancelButton = NO) so I rely completely on the x within the UISearchBar to cancel the existing search. I rely on the Keyboard's "Search" button to dismiss the keyboard (though it's called Done in my case).

When a user searches in my app, I'm disabling a navigation bar button item because it gives a bad user experience, and only when the search has cancelled does the user get the navigation bar button item back. That's all working.

I have one particular scenario though that I cannot get around.

1) Tap on the Search Bar to enter Text

2) Click DONE on the Keyboard and the Keyboard will disappear

3) With the keyboard resigned, the x remains in the UISearchBar

4) Tap the x in the UISearchBar and the text in the SearchBar disappears and the view refreshes

5) At this point, the navigation bar button should be enabled again, but it's not.

Code:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    self.timelineSearchBar.showsCancelButton = NO;
    if ([searchText length] == 0)
    {
        [self.timelineSearchBar performSelector:@selector(resignFirstResponder)
                    withObject:nil
                  afterDelay:0];
    }

I know that the code above is meant to dismiss the keyboard when the x is pressed which is fine.

In my case, the keyboard is already resigned, so I want the tapping of the x to just re-enable the navigation bar item.

    self.addButton.enabled = YES; 

in that if statement above doesn't do anything at all and the navigation bar item is still disabled.

I've even tried in that if statement :

[self.timelineSearchBar performSelector:@selector(enableAdd)
                    withObject:nil
                  afterDelay:0];

- (void)enableAdd
{
    self.addButton.enabled = YES;
}

but that crashes saying searchBar does not respond to that enableAdd selector.

I've done a breakpoint and see that the if statement above does evaluate to true when I tap the x and it goes into the statement, it "runs" the code to enable the button, but it never happens.

Also my end editing method is:

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
    [searchBar setShowsCancelButton:NO animated:YES];
    self.addButton.enabled = YES;
}

UPDATE: I've tried the link here http://engineeringtheworld.wordpress.com/2011/04/11/detecting-when-clear-is-clicked-in-uisearchbar-x-button/ with no success - the textField's shouldClear method doesn't get called. I'm using iOS 7 so perhaps there's another way to embed the views with textFields? This is very possibly the right approach, but it's not working with my code because the for statement in that sample never gets evaluated as true (I put in an NSLog).

UPDATE 2: From if the if statement above, I called the searchBarCancelButton method and I had extreme loops being caused, so that of course wasn't the right approach:

[self performSelector:@selector(searchBarCancelButtonClicked:) withObject:self.timelineSearchBar afterDelay: 0];

Any guidance on this would be really appreciated. I know I'm missing a key step but I just can't quite figure it out.

The problem is that when tapping the X button, searchBar:textDidChange: is called before searchBarShouldBeginEditing:

ie here is the call flow: searchBar:textDidChange: -> searchBarShouldBeginEditing: -> searchBarTextDidBeginEditing: -> searchBarTextDidEndEditing:

textDidChange is setting enabled to YES, but then shouldBeginEditing is disabling it again. This works perfectly for me:

-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    self.addButton.enabled = NO;
}

-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
    if(searchBar.text.length == 0){
        self.addButton.enabled = YES;
    }
}

-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if ([searchText length] == 0)
    {
        [searchBar performSelector:@selector(resignFirstResponder) withObject:nil afterDelay:0];
    }
}

-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    self.addButton.enabled = [searchBar.text length] == 0;
    [searchBar resignFirstResponder];
}
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if([searchText length] == 0 && searchBar.text.length == 0)
    {
        self.addButton.enabled = YES;
        [searchBar performSelector: @selector(resignFirstResponder)
                    withObject: nil
                    afterDelay: 0.1];
    }
}

I'm creating an answer here for clarity, but the answer by Michaels helped massively and is the accepted approach here, although I got my code working.

I did a lot of digging around with NSLogs and interestingly, I discovered that the shouldBeginEditing appeared before the textDidChange (in the order of the NSLogs).

However, I also noticed that in the steps in my original question, with the keyboard dismissed and the UISearchBar containing text and the x visible, if I tapped x, the keyboard didn't appear, but it called shoudlBeginEditing again.

This was the method that was causing the addButton to continue to be greyed out because that method set that button to be disabled.

So I adjusted the code:

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)bar
{
    NSLog(@"Should begin");
    if ([self.timelineSearchBar.text length] > 0)
    {
        self.addButton.enabled = NO;
    }
    else
    {
        self.addButton.enabled = YES;
    }
    self.timelineSearchBar.showsCancelButton = NO;
    BOOL boolToReturn = self.shouldBeginEditing;
    self.shouldBeginEditing = YES;
    return boolToReturn;
}

I put the if condition in there so that the code reacted appropriately if I went back to the searchBar after cancelling with the x.

This way, the add button does not disable as soon as I click on the UISearchBar (which brings up the keyboard). However, in the textDidChange (which is what I saw gets called from the very first letter being typed), I put the following condition too:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    NSLog(@"Text did change");
    self.timelineSearchBar.showsCancelButton = NO;
    if ([self.timelineSearchBar.text length] > 0)
    {
        self.addButton.enabled = NO;
    }
...
}

This way, the UISearchBar would only display the add button when I start typing in a letter. This worked for me because if the user tapped on the UISearchBar and did not type anything in, in the prepareForSegue that went to the view that the Add Entry was calling, I checked if the searchBar isFirstResponder and if so, I resignFirstResponder .

With this in mind, I'm not sure if this is the Apple way of doing things, but it's clean. I'll know soon enough if my app gets rejected because of this, but thanks so much for your help Michaels; you really pointed me in the right direction for an issue that took up my entire afternoon!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM