How to set text in UISearchBar without activating UISearchDisplayController - iphone

I'm using a UISearchDisplayController in my app. When the user selects an item in the search results returned I deactivate the UISearchDisplayController. Deactivating the controller clears the text the user has typed. I want to keep it there. I can force the text back into the UISearchBar by setting it again after the controller has been deactivated.
Like so:
NSString* searchText = self.searchDisplayController.searchBar.text;
[self.searchDisplayController setActive:NO animated:YES];
self.searchDisplayController.searchBar.text = searchText;
Which works.
However, I am seeing a timing issue if I don't animate the deactivate call. Calling
setActive like so:
NSString* searchText = self.searchDisplayController.searchBar.text;
[self.searchDisplayController setActive:NO animated:NO];
self.searchDisplayController.searchBar.text = searchText;
causes the UISearchDisplayController to become active again!
Is there are a way that I can set the text of the UISearchBar without having the UISearchDisplayController that's associated with become active? Any other suggestions to get around this behaviour?

For any one else wondering how to do this I managed to get it working by adding this in my delegate:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
if(!controller.isActive){
controller.searchResultsTableView.hidden = YES;
return NO;
}
controller.searchResultsTableView.hidden = NO;
[....]
return YES;
}

Aaron answer works fine. A simpler way of doing things, by editing your peace of code:
NSString* searchText = self.searchDisplayController.searchBar.text;
[self.searchDisplayController setActive:NO animated:NO];
self.searchDisplayController.delegate = nil;
self.searchDisplayController.searchBar.text = searchText;
self.searchDisplayController.delegate = self; //or any delegate you like!
That way, none of your delegate functions are going to be triggered when setting the search bar text.

In Apple's internal forum someone suggested a workaround of setting the placeholder text of the searchBar to the last search text when the UISearchDisplayController deactivates. It appears in the box, but it's greyed out. Not ideal, but possibly acceptable.

Related

UISearchBar cancel button Xcode 4.3?

How do I get the cancel button to only appear when the user starts entering text into the UISearchBar?
I tried this
- (void)searchBarTextDidBeginEditing:(UISearchBar *)aSearchBar {
self.searchBar.showsCancelButton = YES;
}
But it doesn't work, I don't think there's anything wrong with with setting it to "showsCancelButton" because even when I say
NSLog(#"Typing");
It won't print out to the screen. Is there another method in Xcode 4.3 that can do this?
Is there also a method that knows if the cancel button has been pressed?
Are you sure that the class is the delegate of searchBar? Try setting self.searchBar.delegate=self; in the viewDidLoad method.
Your method is not returning a BOOLean value, 'YES.' This should work:
// show search bar's cancel button when editing
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
searchBar.showsCancelButton = YES;
return YES;
}
// hide search bar's cancel button when not editing
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
searchBar.showsCancelButton = NO;
return YES;
}
Try this:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)aSearchBar {
aSearchBar.showsCancelButton = YES;
}

iPhone UISearchBar takes two clicks to be selected

I have a UISearchBar in my app, and I'm running the following code with it:
- (void)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:YES animated:YES];
}
So when the user clicks the search bar, a cancel button pops up next to it.
This, unfortunately, makes it so the text box isn't selected, and the keyboard doesn't pop up. You have to click the search bar a second time to get those things to happen.
How would I fix this?
Thanks.
The method should be like this:
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:YES animated:YES];
return YES;
}
The key element is returning YES in this method to indicate that it should in fact begin editing.
Documentation here: http://developer.apple.com/library/ios/documentation/uikit/reference/UISearchBarDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UISearchBarDelegate/searchBarShouldBeginEditing:
could you change your code as below
[searchBar setShowsCancelButton:NO animated:YES];
I think your were passing YES in the above method.

Keyboard not showing after MFMessageComposeViewController

In an iPhone app I have a UITextView and a button, which lets the user send the content of the UITextView as a text message. The code looks like this:
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
picker.messageComposeDelegate = self;
picker.body = textView.text;
[self presentModalViewController:picker animated:YES];
Everything works fine, except for when the message is either sent or Cancel is tapped in the MFMessageComposer: The keyboard for the UITextView is not shown anymore, even though the cursor blinks.
I tried a few things, including a [textView resignFirstRepsonder] in both the button code and -viewDidDisappear. [textView becomeFirstResponder] in the MFMessageComposeViewControllerDelegate method or the -viewDidAppear didn't change anything either...
Any ideas?
I had the same issue, and was resigned to accepting fabian's solution, but found that by calling [self dismissModalViewControllerAnimated:NO] and then calling [textView becomeFirstResponder], I was able to make the keyboard reappear. Something about the animation was screwing up the keyboard; looks like a bug in iOS 4.2.
After the view has disappeared, you need to make your view first responder. Add the MFMessageComposeViewControllerDelegate protocol to your header, then use the following:
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result{
[self dismissModalViewControllerAnimated:YES];
[self becomeFirstResponder];
}
Happy coding,
Zane
I had a similar problem and was able to fix it by calling becomeFirstResponder after a slight delay:
[textField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.01];
The delay trick also solves the problem of missing text cursor after showing an UIAlert right after MFMessageComposeViewController finishes, however the delay needs to be much longer (0.5 sec in my case)
I was not able to find a better solution, so here is my fix:
In
- (void) actionSheet:(UIActionSheet *)actionSheet
willDismissWithButtonIndex:(NSInteger)buttonIndex
I dismiss the Keyboard and in
- (void) actionSheet:(UIActionSheet *)actionSheet
didDismissWithButtonIndex:(NSInteger)buttonIndex`
I present the MFMessageComposeViewController.
In
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
I don't do [textView becomeFirstResponder] as it doesn't work. Neither does it work in viewDidAppear:. The user has to tap the UITextField again.
Not a very nice solution but the only one I found...
As of iOS 5, here is one workaround. Before you present the MFMessageComposeViewController instance, resign first responder on your UITextView:
[self presentViewController:messageComposer animated:YES completion:NULL];
[textView resignFirstResponder];
Then in the delegate method messageComposeViewController:didFinishWithResult: do this:
[controller dismissViewControllerAnimated:YES completion:^{
[textView performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0];
}];
This fixed the disappearing keyboard problem for me. Without having to permanently dismiss the keyboard.
This behaviour will not appear if viewController which is shown before modal VC is a child of navigation controller. So solution is to make fake UINavigationController and add your VC controller to nav controller.

Strange UISearchBar cancel button behaviour in iphone (Working fine in Simulator)

I am showing some Lists in UITableView. For sorting purpose i have used UISearchBar. I am getting some strange behaviors of Cancel button
Steps to reproduce
Search for something
Notice that while you are searching, there is a 'Cancel' button that will get rid of the onscreen keyboard.
Now tap into detail of one of the search results
Then go back
The search results are still there, and the search bar is there, but the 'Cancel' button is missing.
So there is no way to remove the onscreen keyboard without closing the application and re-opening.
But these scenario occurring only in iphone not in simulator. I am able to see Cancel button when i go back to first screen.
I have used these delegates:
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
searchBar.text = nil;
[searchBar resignFirstResponder];
isSearch = NO;
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
searchBar.showsScopeBar = NO;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:NO animated:YES];
return YES;
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
searchBar.showsScopeBar = YES;
[searchBar sizeToFit];
[searchBar setShowsCancelButton:YES animated:YES];
isSearch = YES;
return YES;
}
Please help
Try this post.
I would suggest you use UISearchDisplayController - a helpful tutorial?

UITableView crash on updates after text edit

So I'm totally stumped by this one and tempted to call "OS bug".
I have a TableView controller with a single section, and in the header for that section there is an UITextField. Several operations result in rows being added/removed without a problem. However, as soon as text is edited in the header, and the keyboard dismissed, any insertion/removal of rows results in an immediate crash.
And it can actually be simplified further - simply calling beginUpdates/endUpdates on the table once the keyboard is dismissed is enough to cause a crash. The end of the callstack is:
_CFTypeCollectionRetain
_CFBasicHashAddValue
CFDictionarySetValue
-[UITableView(_UITableViewPrivate) _updateWithItems:withOldRowData:oldRowRange:newRowRange:context:]
-[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:]
-[UITableView endUpdates]
I've put together a minimal example that demonstrates the problem.
Complete Controller source: http://www.andrewgrant.org/public/TableViewFail.txt
Example Project: http://www.andrewgrant.org/public/TableViewCrash.zip
Most relevant code:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// create header view
UIView* header = [[[UIView alloc] initWithFrame:CGRectMake(0.f, 0.f, 320.f, 50.f)] autorelease];
// text field
UITextField* textField = [[[UITextField alloc] initWithFrame:CGRectMake(10.f, 12.f, 300.f, 28.f)] autorelease];
textField.text = #"Edit, then 'Save' will crash";
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.clearButtonMode = UITextFieldViewModeAlways;
textField.delegate = self;
[header addSubview:textField];
return header;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
// no purpose, but demonstrates updates work at this point
[self.tableView beginUpdates];
[self.tableView endUpdates];
[textField resignFirstResponder];
// immediate crash
[self.tableView beginUpdates];
[self.tableView endUpdates];
return YES;
}
Just an update - I submitted a bug report and repro case to Apple and they confirmed it's a bug in iOS 4.0. As of iOS 4.1 beta 2 it had not been fixed.
My work around was to turn the first row of my table into a pseudo header that occupies the entire content view and has a custom height. It's not quite as good (things cant reach to the edge of the screen for example) but it's close and doesn't crash.
I hit this bug last night and spent a few hours this morning trying to figure it out. The other answers in this thread didn't work for me, but did help me come up with a workaround that I think is best.
Cameron suggested making an offscreen UITextField the firstResponder, then resigning it before calling endUpdates on the tableview. This didn't work for me, but it gave me an idea.
In the context of my custom header view, I re-parent the text field (in my case, a UISearchBar, actually) before calling resignFirstResponder. Then I put it back:
[self.window addSubview: sb];
[sb resignFirstResponder];
[self addSubview: sb];
a few lines later, when I call [tableView endUpdates], it no longer crashes.
Edit: It just got a bit more complicated. The problem is that if first-responder status is otherwise revoked (for example, the user dismisses the keyboard), this parent-swapping code isn't executed, and we'll eventually get the crash. My current fix is to place a category-override on UITextField resignFirstResponder -- seems to work but not sure yet if there are any adverse side effects.
#implementation UITextField (private)
- (BOOL) resignFirstResponder
{
UIView* superviewSave = self.superview;
[self.window addSubview: self];
BOOL success = [super resignFirstResponder];
[superviewSave addSubview: self];
return success;
}
#end
Taking Tom's solution one step further, I noticed this solution only works on iOS 4.X, which is ok because this problem only exists in iOS 4.X. Therefore I changed his method to:
#implementation customUITextField
- (BOOL)resignFirstResponder {
if ( [[UIDevice currentDevice].systemVersion characterAtIndex:0] == '4' ) {
UIView* superviewSave = self.superview;
[self.window addSubview:self];
BOOL success = [super resignFirstResponder];
[superviewSave addSubview:self];
return success;
}
return [super resignFirstResponder];
}
#end
I came across this bug myself and am so glad I found your post because I was banging my head on my desk trying to figure out where I screwed up.
For my workaround, I created an offscreen UITextField and called becomeFirstResponder and then resignFirstResponder on that text field before doing the updates. This avoided the crash and didn't require any redesign of the headers or cells.