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.
Related
i have a screen having navigation controller and text field. when i move next and come back i want the keyboard should be hidden in first screen. I am hiding keyboard like on textfield event.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
But how to do that in View related events so that whenever my view appears keyboard is hidden..
Pls guide/Help.
thanks in adv.
I think this is also a good way to remove keyboard with in iOS App if your UITextView or UITextField not connected through the IBOutlet.
If you want to Hide Keyboard with UIViewController LifeCycle Events like with viewWillAppear or etc. Follow this
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self view] endEditing:YES];
}
Otherwise if you object connected using IBOutLet this code will work fine as you describe too.
[yourTextField resignFirstResponder];
Add this code to your ViewWillAppear :
for(id obj in self.view.subviews)
{
if([obj isKindOfClass:[UITextField class]])
{
[obj resignFirstResponder];
}
}
This would take in all the textfields in that particular view here it is the whole view and add the code you had written previously for removing the keyboard.
A good habit is to write this code in your screen's -viewWillDisappear. So, when you navigate from one screen to another at that time it will remove the keyboard from that screen.
- (void)viewWillDisappear:(BOOL)animated
{
[self.view endEditing:YES];
[super viewWillDisappear:animated];
}
For multiple textFields, it is better to use -endEditing for that particular view instead of -resignFirstResponder for any single textField. Take a look at my Answer.
//This is for Swift
override func viewWillAppear(animated: Bool)
{
self.view.endEditing(true)
}
The thing that you are doing wrong is , when you are moving back previous controller to the current controller , the keyboard is up due to the selected textfield of previous controller .
And in the current controller the code:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self view] endEditing:YES];
}
It will not work as no textfield is selected at this controller. So what you need to do is write the same code in the previous controller viewWillDisappear Method it will surely resolve your Problem .
- (void)viewWillDisappear:(BOOL)animated
{
[self.view endEditing:YES];
[super viewWillDisappear:animated];
}
I have two textfields which are of type UITextField.
I have two buttons click and cancel.
The idea is to enter two numbers and it will navigate to next view. This View should display those two numbers.
The problem is if I click on the textfield one then the keypad is responding; when I click return it does not jump to the next field.
-(BOOL)textFieldShouldReturn:(UITextField *)textField{[textField resignFirstResponder];return YES;}
You need to connect UITextFiled Delegate from nib or programeticuly like this image:
or
other way is programmatic like in your viewDidLoad method or viewWillAppear method:
Yourtxtfild.delegate = self;
EDIT
for jumping AnotherView Use this textfiled delegate method:-
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
//you can set your textfiled string in to globle Variable and use it in another viewController
YourViewCntroller *objViewController = [[YourViewCntroller alloc] initWithNibName:#"YourViewCntrollernib" bundle:nil];
[self.navigationController pushViewController:objViewController animated:YES];
}
You have to set the delegate of the textfield as the object of the class where you have written the textFieldShouldReturn: method.
#Ragavan : You are just resigning the first textfield, but you are not making the other textfield to respond. So, use the code below as reference to make it work.
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField1 resignFirstResponder];
[textField2 becomeFirstResponder];
return YES;
}
I have a UIView with a UITextView and UITextField as a subview. I want the keyboard to appear automatically on textFieldShouldReturn call.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
[textView becomeFirstResponder];
return YES;
}
but this does not work AND for some reason, it displays keyboard with cursor on next line in text view . I tried to set text nil in textview but it automatically call textDidChange method and cursor moves on new line without any text.
This same technique works correctly for a UITextField and also it works fine with iOS 5.0 but how to fix this in iOS 4.3. Let me know if you have any alternative as well.
Am I missing something obvious?
There's a known bug in iOS with resigning and becoming first responder within the same runloop. Try the following
[textField resignFirstResponder];
[textView performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
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.
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.