Focus on next valid key view on iPhone - iphone

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/

Related

How to identify which textfield is currently first responder

If you have several text fields on the screen, and the keyboard pops up for each one when they are tapped, what if you want to programmatically hide the keyboard, or resign first responder, but you don't know which textfield to send the resignFirstResponder message to? Is there a way to identify which object/textField should get this message?
check all of your textfield call
[textfield isFirstResponder]
You could keep track of which text field is the first responder by either setting your view controller to be the delegate object of all text fields and then when your subclassed text fields gets the "becomeFirstResponder" method call, tell your view controller which text field is the current one.
Or, there's a more blunt force approach which is a category extension to "UIView":
#implementation UIView (FindAndResignFirstResponder)
- (BOOL)findAndResignFirstResponder
{
if (self.isFirstResponder) {
[self resignFirstResponder];
return YES;
}
for (UIView *subView in self.subviews) {
if ([subView findAndResignFirstResponder])
return YES;
}
return NO;
}
#end
which I got from this potentially very related question.
You Can Check Your all TextField and than Identify Easily.
[textfield isFirstResponder];
There is no public method to get the current first responder, but you can do things to still get it; The first one is obviously to keep track of this yourself. You can do this in various way and if you don't want to touch any existing class but just want it to work, a category and method swizzling will do the trick. The more cleaner solution however is to iterate through the view hierarchy and ask the views wether they are the current first responder. You can start with the root UIWindow and start iterating, or you can start with your current UIViewController's view, but keep in mind that the current first responder doesn't have to be part of your roots UIWindow view hierarchy (eg. if you have a text field inside an UIAlertView).
Try this (Swift 3):
if textField.isEditing {
textField.resingFirstResponder()
}

How can I make an unknown UITextField resign first responder?

My view has two UITextFields and a UISwitch. If a user is edits a textField, and then immediately touches the switch (without pressing return), the text is left as they typed it, without AutoCorrect.
If I know which textField they were typing in, I can force the autocorrect to complete by calling [textField resignFirstResponder]. But the user could be typing in either textField, so I don't know which one to call.
How can I get around this? Is there a way of detecting which textField was being used? Or something simpler I haven't thought of?
One lovely way of doing this without having to keep track of which field is active:
// This causes the current responder (eg. an input field) to resignFirstResponder and
[self.endEditing:YES];
Replace [self.view endEditing:YES] with the below one...
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
The uitextfielddelegate methods are called for the textfield on which the editing is in progress. So that way you needn't be facing the problem of detecting which text field is being edited.
So implement the uitextfielddelegate methods and assign the delegate of the text field to the class where you implement the methods and handle the responses in them.
The methods which you should be interested in are:
textFieldDidEndEditing:
Tells the delegate that editing stopped for the specified text field.
- (void)textFieldDidEndEditing:(UITextField *)textField
Parameters
textField
The text field for which editing ended.
Discussion
This method is called after the text field resigns its first responder status. You can use this method to update your delegate’s state information. For example, you might use this method to hide overlay views that should be visible only while editing.
Implementation of this method by the delegate is optional.
Availability
Available in iOS 2.0 and later.
Declared In
UITextField.h
You may keep track yourself which one is the current one, by using the textFieldDidBeginEditing delegate.

iPhone SDK: resignFirstResponder not working

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];
}

iPad popover textfield - resignFirstResponder doesn't dismiss 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!

Hiding the Keyboard

I have a UISearchBar and on the delegate method I hide the keyboard when the text field is cleared:
- (void)searchBar:(UISearchBar *)filterBar textDidChange:(NSString *)filterText {
NSLog(#"filter: %#", filterText);
if ([filterText length] == 0) {
NSLog(#"hiding keyboard");
[filterBar resignFirstResponder ];
Now when I use the backspace button to clear out the search term all is good. The keyboard hides when the search turns to empty. Not so when I am pressing the "cross" button to clear out the search field altogether.
Well, not entirely true. I does call resignFirstResponder and hides the keyboard - you just can't see it because it comes right back up. I found this out by observing the keyboard show/hide events.
So how come the keyboard is shown again? How can I prevent this?
I've already tried to walk all subviews of the UISearchBar and also call resignFirstResponder on those ...but unless I did something wrong - that doesn't solve this either.
Update:
In fact I just got the keyboard to not disable the "Done" button :-D ...so I will "stop" going down that road as Kevin suggested. Still I would like to know why the keyboard came back up like this.
I would suggest you stop trying to do this. Hiding the keyboard when the field empties out is completely non-standard behavior and the user won't expect it. In situations like this it's far better to keep your behavior consistent with all the rest of the apps across the system.
I see you've accepted an answer and don't plan to continue in this vein, but I am curious whether you could achieve something like you wanted by implementing this:
- (BOOL)canBecomeFirstResponder
{
return !preventingKeyboardAppearance; // so to speak
}
- (void)searchBar:(UISearchBar *)filterBar textDidChange:(NSString *)filterText
{
// handle text
preventingKeyboardAppearance = YES;
[filterBar resignFirstResponder];
}
I'm not clear under what circumstances you would set preventingKeyboardAppearance back to NO, but I do wonder if this would work.
I basically agree with Kevin, but that doesn't help you so here goes:
Try looping through the subviews of the searchbar and find the sibling which is of the class UITextField. Then either set the delegate property of this text field to your ViewController's class and handle the callback there (e.g. textViewShouldReturn), or simply call resignFirstResponder directly on the text field. The former obviously needs to be done at init/load time while the latter can be done in your existing textDidChange callback.
Here are some more pointers:
http://discussions.apple.com/thread.jspa?threadID=1479468&tstart=0
http://discussions.apple.com/thread.jspa?messageID=8176608
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
[textField resignFirstResponder] is not working some time so use this
[YorTextFieldName resignFirstResponder] it's working correctly not any other
function for hiding key bord