I have a view that supports copy and shows the edit menu using the following code:
if ([self becomeFirstResponder]) {
// bring up edit menu.
UIMenuController *theMenu = [UIMenuController sharedMenuController];
[theMenu setTargetRect:[self _textRect] inView:self];
[theMenu setMenuVisible:YES animated:YES];
}
The problem is, that when becomeFirstResponder gets called, the keyboard get's hidden. A good example of the correct behavior is in the SMS app. Double tap a message while the reply box is visible and the reply box looses focus, but the keyboard stays in place. Also, when the bubble is deselected, the reply box regains focus.
Unfortunately, Apple can do a lot of things that are not available to third-party apps.
I believe what you want is possible in iOS 3.2+ if you make the view that is to become the first responder accept keyboard input. You do that by having your view class adopt the UIKeyInput protocol:
A subclass of UIResponder can adopt this protocol to implement simple text entry. When instances of this subclass are the first responder, the system keyboard is displayed.
The protocol consists of 3 required methods that you have to implement. In your case, you would probably apply the inputs you receive in these methods to your text field and make it the first responder again. I haven't tried this but it should work.
Related
I'm working on an app that at some point requires keyboard input. My app uses OpenGL ES for display, and I have my own graphics framework that can display a text field, and knows how to manage the cursor and render text. This code works great on other platforms that have a physical keyboard, like Windows and OS X.
All I need to get the iOS version of my app working is to be able to bring the keyboard up and down programmatically, and also to get the key press events from the user into my view so that I can then route them into my framework's own event system.
I saw this question, but I could not make the solution depicted there work. Not sure if it is because I'm doing something wrong, or because it doesn't work on current iOS releases.
EDIT: It would be as helpful to be pointed at a working app with source code that creates any UI element programmatically and displays it on top of a GL ES screen. I think I can figure the rest out if I get that part understood.
I can't point you at a working example, but I believe what you're looking for is here http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIKeyInput_Protocol/Reference/Reference.html#//apple_ref/occ/intf/UIKeyInput
The basic idea is that you implement the UIKeyInput protocol on a UIResponder object, such as a UIView. Make the view the firstResponder and the keyboard should automatically appear. The UIKeyInput protocol gives you simple feedback for inserting a character and deleting a character when the user presses buttons on the keyboard.
This isn't working code, but it would look something like this:
#interface MyKeyboardView : UIView <UIKeyInput>
#end
#implementation MyKeyboardView
- (void)insertText:(NSString *)text {
// Do something with the typed character
}
- (void)deleteBackward {
// Handle the delete key
}
- (BOOL)hasText {
// Return whether there's any text present
return YES;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
#end
when the view is attched, make it the first responder to show the keyboard
[myView becomeFirstResponder];
or resign first responder to dismiss the keyboard
[myView resignFirstResponder];
Edit: make sure your view is attached to the view hierarchy or this probably won't do anything.
I have subclassed TTMessageController and remove the _fields and _fieldViews, so basically it has just the textEditor in it, and i wanted the textEditor to become the First Responder so that the keyboard will appear, but still i cant make it work.. It only appear when I started typing from the keyboard (using Simulator not the iPhone's keyboard)...
Try this, I think it will work: Override -[viewWillAppear:], and call super and then call [_textEditor becomeFirstResponder] to set focus to the textEditor:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[_textEditor becomeFirstResponder];
}
The reason you need to do this is that in a normal TTMessageController, -[TTMessageController viewWillAppear:] sets keyboard focus to one of the fields, but in your case there are no fields, and you want to instead set focus to the text editor.
For some reason, resignFirstResponder is not working. I am not sure why? I have tried to call it from textFieldDidEndEditing and nothing happens. A NIB is being used and each's delegate is pointing to files owner.
What needs to be done to get the keyboard to dismiss?
Thanks.
Don't use -textFieldDidEndEditing. That's called after the text field resigns firstResponder status, which is what you're trying to use it as a hook to make happen. Cart before horse, chicken-and-egg kind of problem.
Instead use -textFieldShouldReturn to get triggered when the return key is pressed (and remember to return YES; from that.) Also float a clear custom button behind the elements of the view and handle a "background tap" that goes through all the text fields on your view and resigns first responder on the lot of them.
actually you should return NO so that the text field does not begin editing at all. If it does, the firstresponder gets set and the keyboard pops up again.
Make sure your setting your delegates for the textfield.
myTextField.delegTe = self;
And you are using in your header:
<UITextFieldDelegate>
EDIT:
Try:
if(textField == myTextField){
[textField resignFirstResponder];
}
Is there an iPhone equivalent for the NSResponder methods -selectNextKeyView or -nextValidKeyView from Mac OS X? I know about the -becomeFirstResponder method, but finding out which view to call that on is not very pretty when view hierarchies get more complicated.
There must be some kind of way to find this out as when I press tab when in the iPhone Simulator, focus does properly go to the next UITextField. This made me wonder what exactly happens when I press tab. Any ideas?
Update: This does exactly what I want, but _nextKeyResponder is private API, so a no-no. Is there any way to do a 'fake' tab key press without using private API?
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// Try to find next responder
UIView *nextResponder = (UIView *)[self.view _nextKeyResponder];
if (nextResponder) {
// Found next responder, so set it.
[nextResponder becomeFirstResponder];
[self.tableView scrollRectToVisible:[self.tableView convertRect:[nextResponder frame] fromView:nextResponder] animated:YES];
} else {
// Not found, so remove keyboard.
[textField resignFirstResponder];
}
return NO; // We do not want UITextField to insert line-breaks.
}
There is not a public iOS equivalent for NSResponder's -selectKeyView or -nextValidKeyView.
When the first responder is an instance of UITextField, pressing tab instantiates a private subclass of UIEvent which is passed to -[UIApplication sendEvent:], which in turn calls -[UIView _nextKeyResponder].
-[UIView _nextKeyResponder] doesn't work quite the way you think it does. It treats the key view chain as a loop, so your else block will never be reached. For the same reason, even if there was a public API for synthesizing keyboard events, you probably wouldn't want to use it.
Instead, you probably want something more like UIWebView's UIToolbar-based form input accessory. Its buttons can be enabled and disabled when appropriate, and its delegate handles the actual button press actions.
To implement such a delegate in a general way, however, it might be helpful to look at how -[UIView _nextKeyResponder] is implemented.
In the UITextField delegate -textFieldDidEndEditing:, switch between the various text fields (for example, by testing the text field's tag property).
When you match one text field, set another text field or other control to become the next responder.
I'm surprised nobody else appears to have solved this on iOS.
I devised a solution that handles both Tab and Shift+Tab to go forward and backward to any field you want on iOS, and doesn't use any private APIs.
Here is the write-up: http://weaklyreferenced.wordpress.com/2012/11/13/responding-to-the-tab-and-shift-tab-keys-on-ios-5-ios-6-with-an-external-keyboard/
I have two text fields email and password. The following code works fine when the fields are presented on a regular view but when they are on a popover, the resignFirstResponder does not work (becomeFirstResponder works). textFieldsShouldReturn was called for both fields.
Any idea if I am missing something?
Thanks!
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
if (theTextField == email) {
[password becomeFirstResponder];
return NO;
}
[theTextField resignFirstResponder];
return NO;
}
Check this question:
Overriding disablesAutomaticKeyboardDismissal to return NO as below fixed the same problem of mine. You should put this code to your view controller, from which you initiate the keyboard:
- (BOOL)disablesAutomaticKeyboardDismissal {
return NO;
}
As described in this answer, the keyboard will sometimes remain on-screen when the view is presented with the UIModalPresentationFormSheet style.
I'm not too sure about this, but, as I understand the responder hierarchy, resign would work only if you have some other responder to answer.
In a regular view, the view itself is willing. In a popup, maybe you need to do something to your popup class (like reimplement some Responder methods) in order for this to work.
I was also having this problem. But I solved this by making a another control, which is not in the popover as firstResponder and later a resigned it from there. But I don't what is the problem with popover.
The answer is provided as a possible solution to others with a similar problem, but where the conventional remedies don't work.
In summary -
I had a similar problem (under a certain condition) and tried everything - to no avail - Included in my list of possible solutions was [obj's resignFirstResponder], the overriding of 'disablesAutomaticKeyboardDismissal' for my view controller, [self.view endEditing:YES]; and a bunch of other things.
Went about determining the [id] of the current first responder, only to discover it was nil. Tapping 'Done' on the keyboard or using any of the methods above did nothing - the keyboard remained - even after tapping on another input field.
The screen was essentially a ViewController with a UITableView with a text input field in each cell - 7 or 8 in total. Tapping on any cell would bring up keyboard as expected and tapping a separate 'Next' button (to hide the keyboard plus other processing) worked as expected.
However, in landscape mode, the last field was covered by the keyboard requiring the table to be scrolled to reveal such.
After scrolling and tapping that last input field, the keyboard could not be dismissed - no matter what. The only work around was to scroll the table back under the keyboard, then tap the 'next' button. It doesn't make sense.
Almost at the point of giving up (and implementing a workaround), the solution that worked was to make that last input field the firstResponder (even though it already had a blinking cursor) and then to resignFirstResponder after that.
So;
`-(void) actionNext {
[[m_arrInputFields objectAtIndex:7] becomeFirstResponder];
[[m_arrInputFields objectAtIndex:7] resignFirstResponder];
}`
fixed the problem - whereas [m_arrInputFields objectAtIndex:#any other index#] did not!
Would be great if anyone can provide clarity or an explanation for this - else - I hope it saves someone else a few hours of work!