I'm debugging my code, where UISearchBar's delegate method searchBarTextDidBeginEditing: is called exactly twice every time I tap on the search bar (which is in the navigation bar).
The odd thing is that only this delegate method is called twice. The others are called only once within the whole proccess, which is the correct behavior.
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
// called only once
return YES;
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
// called twice every time
[searchBar setShowsCancelButton:YES animated:YES];
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
// called only once
[searchBar setShowsCancelButton:NO animated:YES];
return YES;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
// called only once
}
Any idea what could be wrong?
The UISeachrBar is set up in Storyboard, with properly connected outlets, although it's not added to any view, and in the particular view controller's viewDidLoad is the following line that adds the search bar to the navigation bar:
self.searchDisplayController.displaysSearchBarInNavigationBar = YES;
I'm using Xcode 5.0.1 and running the code in iOS 7.0.3 Simulator.
I was experiencing the same issue, and dug in a bit deeper.
In my case, I had a subclass of UISearchDisplayController which functioned as UISearchDisplayDelegate for itself, and UISearchBarDelegate for its UISearchBar.
As it turns out, the problem is that UISearchDisplayController implements the following methods that collide with theUISearchBarDelegate` protocol:
- (void)searchBar:(id)arg1 textDidChange:(id)arg2;
- (void)searchBarCancelButtonClicked:(id)arg1;
- (void)searchBarResultsListButtonClicked:(id)arg1;
- (void)searchBarSearchButtonClicked:(id)arg1;
- (void)searchBarTextDidBeginEditing:(id)arg1;
This means if you make a UISearchDisplayController the delegate of its own UISearchBar, those methods will be called twice.
I found that if you unset the searchBar delegate and only keep the searchDisplayController delegate the method is not called at all any more. So the only workaround i could come up with is putting this in the beginning of your searchBarTextDidBeginEditing and searchBarTextDidEndEditing.
static NSDate *lastInvocation;
if ([[NSDate date] timeIntervalSinceDate:lastInvocation] < 0.1f) {
lastInvocation = [NSDate date];
return;
} else {
lastInvocation = [NSDate date];
}
I found this solution:
[searchBar setShowsCancelButton:NO animated:YES];
[searchBar resignFirstResponder];
But funny thing is, I removed it after some two rounds of testing, the code is just called once, not twice
I had problem with searchBarSearchButtonClicked: method been called twice.
Problem was solved by calling [searchBar resignFirstResponder];
#pragma mark - UISearchViewDelegate methods
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
// Do things
[searchBar resignFirstResponder];
}
Related
I have one view in my app where there is 1 text field. And I've noticed that keyboard appears after second tap.
But it's interesting that on iPhone it's time to time (some time appears after first tap at once, and some time after second tap only).
On iPad looks like it more ofter appears after second tap only.
I use UITextFieldDelegate
in viewDidLoad I assign the delegate _locationTextField.delegate = self;
and I use delegate methods textFieldDidBeginEditing, textFieldDidEndEditing, textFieldShouldReturn
e.g.:
#pragma mark -
#pragma mark UITextFieldDelegate
- (void)textFieldDidBeginEditing:(UITextField *)textField {
_locationNameBeforeManualEdit = _locationTextField.text;
// save the previod city value to compare after did end editing
NSLog(#"textFieldDidBeginEditing");
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"textFieldDidEndEditing");
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self continueButtonPressed:nil];
// [textField resignFirstResponder];
return YES;
}
in storyboard
What could be the problem?
Found solution here on Stackoverflow - solution related with keyboard preload:
- (void)preloadKeyboard {
UITextField *lagFreeField = [[UITextField alloc] init];
[self.window addSubview:lagFreeField];
[lagFreeField becomeFirstResponder];
[lagFreeField resignFirstResponder];
[lagFreeField removeFromSuperview];
}
This method should be used in application: didFinishLaunchingWithOptions: method of AppDelegate.
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:
i.e. 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!
I have a ViewController with a subview that contains a UISearchBar. When I click on the search bar the keyboard appears and I am able to close it using the cancel button. The problem seems to be that it isn't accepting any of the input when a user clicks on the keyboard buttons.
#pragma mark -
#pragma mark SEARCH METHODS
#pragma mark -
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
self.mainSearchBar.showsCancelButton = YES;
return YES;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[self.mainSearchBar resignFirstResponder];
self.mainSearchBar.showsCancelButton = NO;
self.mainSearchBar.text = #"";
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self.mainSearchBar resignFirstResponder];
}
Has anyone had this issue before or know how to fix it?
** UPDATE *****
It turns out the Siri will work when trying to edit the UISearchBar. Still no luck with the keyboard input though. I think it has something to do with the fact that the UISearchBar is situated on a UIView that is then added as a subview. Not sure how to fix it though.
** UPDATE 2 *****
Moved the search box to the main UIView and I am still getting the same error. I am wondering if it is now related to the Navigation Controller.
Make sure that the app delegate has a [self.window makeKeyAndVisible]. Hopefully it will solve your problem.
Check whether you have added a UISearchBarDelegate in your viewController's .h file.
Try this code also:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSLog(#"%#",searchText);
}
This has to be related to how the SearchBar is rendered in relation to the ViewController's view. Why are you making the SearchBar a subview of another view rather than a subview of the ViewController's view?
Problem solved, the answer was found on a previous thread Keyboard and cursor show, but I can't type inside UITextFields and UITextViews
It turns out that in IOS6 the Visible at Launch check needs to be clicked on the options.
I have a UITableView with CustomCells which contain a TextField. Look at the pictures which i have uploaded.
Picture1 Picture2
I want that if i start to scroll the keyboard should hide.
I tried it with
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"Got called");
ProductTableCell *cell;
[cell.mengeTextField resignFirstResponder];
}
Console-Log:
2012-04-24 12:57:48.924 Book-App[21029:15803] Got called
2012-04-24 12:57:50.535 Book-App[21029:15803] Got called
2012-04-24 12:57:51.681 Book-App[21029:15803] Got called
But this is not working for me.
Is there a other solution?
Your problem is what Arcank said, cell is not defined.
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"Got called");
ProductTableCell *cell;// <---this cell is nil
[cell.mengeTextField resignFirstResponder];
}
Now if you cannot access the cell, there is a way to cheat. Simply put something else a first responder, then resign it right away.
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
NSLog(#"Got called");
[scrollView becomeFirstResponder];
[scrollView resignFirstResponder];//You might not even need this (not sure)
}
This would take care of your problem. If scrollView cannot become first responder just use other things that can. (improvise).
Edit: Just read you and Aalok Parikh comments, this is pretty much what he is trying to say.
use this method tableView:willDisplayCell:forRowAtIndexPath: this will solve your problem
In your code, cell never gets set. It's nil. So the -resignFirstResponder message has no effect.
implement this method
- (void)textFieldDidEndEditing:(UITextField *)textField{
[textField resignFirstResponder];
}
I have a UISearchBar. I want the the keyboard to go away as soon as user hits search...i did try resignFirstResponder but that didn't work. any help would be appreciated
- (void)viewDidLoad {
[super viewDidLoad];
self.title = NSLocalizedString(#"Songs", #"Search for songs");
NSMutableArray *array = [[NSArray alloc]initWithObjects: #"Book_1", #"Book 2", #"Book _ 4", nil];
self.booksArray = array;
[array release];
search.delegate=self;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
thanks
TC
Please make sure of following things.(I hope you are talking about search Button of keyboard.)
You have connected your IBOutlet of searchBar with its variable search.
You are not de-referring search variable anywhere in your code(reassigning it).
Your - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar method is in same viewcontroller as searchBar is in.
Please NSLog(#"Search Bar Instace : %#",search); in viewDidLoad method and searchBarSearchButtonClicked and verify that both instances are same if not then you are search is getting reassigned somewhere in code.
Just after [searchBar resignFirstResponder]; NSLog(#"isFirstResponder : %d",[searchbar isFirstResponder]); and NSLog(#"Next Responder : %#",[searchBar nextResponder]);
Is - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
method is being called when you tap search Button of keyboard? Make sure there are no keyboard responder(like textField,textView or other searchBar) is added behind your searchBar may be unintentionally. Please check it through xib also.
Thanks,
It should work by implementing the respond methods at the delegate object:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
Reference: http://www.iphonedevsdk.com/forum/iphone-sdk-development/7148-problem-uisearchbar-navigation-controller.html#post59467