Ours is a health care app. We have a HIPAA-compliant speech recognizer in the app through which all the dictation can take place. The hospitals don't want physicians to accidentally start speaking to the Nuance Dragon server which is not HIPAA-compliant. So, I was looking for ways I could supress the dictation key on the keyboard.
I tried putting a fake button on the Dictation button on the key pad, but on the iPad the split dock concept keeps moving the microphone all over the screen. This does not sound like a reasonable solution. Are there any experts out there who could help me?
OKAY, finally got it! The trick is to observe UITextInputMode change notifications, and then to gather the identifier of the changed mode (Code seems to avoid the direct use of Private API, though seems to require a little knowledge of private API in general), and when the mode changes to dictation, resignFirstResponder (which will cancel the voice dictation). YAY! Here is some code:
Somewhere in your app delegate (at least that's where I put it)
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(inputModeDidChange:) name:#"UITextInputCurrentInputModeDidChangeNotification"
object:nil];
And then you can
UIView *resignFirstResponder(UIView *theView)
{
if([theView isFirstResponder])
{
[theView resignFirstResponder];
return theView;
}
for(UIView *subview in theView.subviews)
{
UIView *result = resignFirstResponder(subview);
if(result) return result;
}
return nil;
}
- (void)inputModeDidChange:(NSNotification *)notification
{
// Allows us to block dictation
UITextInputMode *inputMode = [UITextInputMode currentInputMode];
NSString *modeIdentifier = [inputMode respondsToSelector:#selector(identifier)] ? (NSString *)[inputMode performSelector:#selector(identifier)] : nil;
if([modeIdentifier isEqualToString:#"dictation"])
{
[UIView setAnimationsEnabled:NO];
UIView *resigned = resignFirstResponder(window);
[resigned becomeFirstResponder];
[UIView setAnimationsEnabled:YES];
UIAlertView *denyAlert = [[[UIAlertView alloc] initWithTitle:#"Denied" message:nil delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil] autorelease];
[denyAlert show];
}
}
you can create your own keyboard and set the inputView for the text fields that will accept this dictation. then when they press any keys they will get your keyboard, therefore you dont have to override the keys on the standard keyboard, you will be able to customize the entire thing.
self.myButton.inputView = self.customKeyboardView;
here is an example of an extremely custom keyboard
http://blog.carbonfive.com/2012/03/12/customizing-the-ios-keyboard/
Ray also has a teriffic tutorial on custom keyboards.
http://www.raywenderlich.com/1063/ipad-for-iphone-developers-101-custom-input-view-tutorial
I hope that helps.
I had the same issue and the only way i found that hides the dictation button is changing the keyboard type.
For me changing it to email type seemed to be reasonable:
textField.keyboardType = UIKeyboardTypeEmailAddress;
You could make a subclass of UITextField/UITextView that overrides insertDictationResult: to not insert anything.
This won't prevent the information being sent, but you could then display an alert informing them of the breech.
This is a Swift 4 solution based on #BadPirate's hack. It will trigger the initial bell sound stating that dictation started, but the dictation layout will never appear on the keyboard.
This will not hide the dictation button from your keyboard: for that the only option seems to be to use an email layout with UIKeyboardType.emailAddress.
In viewDidLoad of the view controller owning the UITextField for which you want to disable dictation:
// Track if the keyboard mode changed to discard dictation
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardModeChanged),
name: UITextInputMode.currentInputModeDidChangeNotification,
object: nil)
Then the custom callback:
#objc func keyboardModeChanged(notification: Notification) {
// Could use `Selector("identifier")` instead for idSelector but
// it would trigger a warning advising to use #selector instead
let idSelector = #selector(getter: UILayoutGuide.identifier)
// Check if the text input mode is dictation
guard
let textField = yourTextField as? UITextField
let mode = textField.textInputMode,
mode.responds(to: idSelector),
let id = mode.perform(idSelector)?.takeUnretainedValue() as? String,
id.contains("dictation") else {
return
}
// If the keyboard is in dictation mode, hide
// then show the keyboard without animations
// to display the initial generic keyboard
UIView.setAnimationsEnabled(false)
textField.resignFirstResponder()
textField.becomeFirstResponder()
UIView.setAnimationsEnabled(true)
// Do additional update here to inform your
// user that dictation is disabled
}
Related
I have an application that uses UIAlertView in its login Window normally:
self.customAlert = [[IFCustomAlertView alloc] initWithTitle:#"Save Password"
message:#"¿Do you want the app to remember your password?"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:#"Cancel", nil];
The problem is... Since I updated my devices to iOS8 whenever this alertView comes up it shows the keyboard and I can't dismiss it. On iOS7 this doesn't happen.
I am resigning the responders of user and password when the send button is tapped:
-(IBAction)btnSendTapped:(id)sender{
[self.tfpass resignFirstResponder];
[self.tfuser resignFirstResponder];
}
I have tried:
[self.view endEditing:YES];
and in some alertViews it does work but in others it doesn't. My AlertViews never have text fields so I think there's no reason for this keyboard to appear.
Also the intro button on the keyboard doesn't hide it, so sometimes the OK and Cancel buttons are obstructed by the keyboard and I can't do nothing on the screen.
I think this may have something to to with the UIAlertView deprecation, but I don't know.
I also have these methods implemented:
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return true;
}
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField{
return YES;
}
Any help would be appreciated.
I borrow solution from this blog
For me the keyboard always show up when the alertView.show() has been called.
My solution is using the didPresentALertView method for make sure this will called after the alert view popup. Then we can loop through all UIWindows and it's subviews. I detect it by description name (You can use more accurate method if you want) and just simply remove it from superview.
func didPresentAlertView(alertView: UIAlertView) {
var tempWindow: UIWindow;
var keyboard: UIView;
for var c = 0; c < UIApplication.sharedApplication().windows.count; c++ {
tempWindow = UIApplication.sharedApplication().windows[c] as! UIWindow
for var i = 0; i < tempWindow.subviews.count; i++ {
keyboard = tempWindow.subviews[i] as! UIView
println(keyboard.description)
if keyboard.description.hasPrefix("<UIInputSetContainerView") {
keyboard.removeFromSuperview()
}
}
}
}
Hope this thelp.
Because the keyboard hides the textfields when coming up I implemented a solution for this. Now I also have built in the possibility that the user taps on the next button of the keyboard and directly jumps to the next textfield (tabbing between fields).
The problem now is that the view doesn't scroll if I use becomeFirstResponder only. The keyboard is up but the UIKeyboardDidShowNotification is not triggered and so the view doesn't slide up.
Can I fake such a notification so that the UIKeyboardDidShowNotification is sent by the notification center?
Another option is to use two great libraries for this. BSKeyboardControls for the tabbing and TPKeyboardAvoiding for moving the view.
If you just want to send the notification my guess is that [[NSNotificationCenter defaultCenter] postNotificationName: UIKeyboardDidShowNotification object:self] should work just fine.
The solution is simple:
resignFirstResponder
becomeFirstResponder
I can only provide the solution for C# (that's why I left it out first):
private bool TextFieldShouldReturn (UITextField textfield)
{
if (textfield.Tag == 1) {
UIResponder nextResponder = this.View.ViewWithTag (2);
textfield.ResignFirstResponder ();
nextResponder.BecomeFirstResponder ();
} else if(textfield.Tag == 2){
textfield.ResignFirstResponder ();
loginButton.SendActionForControlEvents (UIControlEvent.TouchUpInside);
} else {
// Not found, so remove keyboard.
textfield.ResignFirstResponder ();
}
return false; // We do not want UITextField to insert line-breaks.
}
I set some tags on each textfield. Than I use the delegate usernameText.ShouldReturn += TextFieldShouldReturn; to call my method TextFieldShouldReturn. This method selects the next textfield. To jump to the next text field you first dismiss the keyboard with resignFirstResponder and present the keyboard with becomeFirstResponder. With this code the UIKeyboardDidShowNotification is called like the user would tap on the textfield (= simulated tap).
#implementation
UIAlertView *query;
#end
- (void)viewWillAppear:(BOOL)animated {
query = [[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"New", #"")
message:nil
delegate:self
cancelButtonTitle:NSLocalizedString(#"Cancel", nil)
otherButtonTitles:NSLocalizedString(#"OK", #""), nil];
query.alertViewStyle = UIAlertViewStylePlainTextInput;
UITextField *textField = [_query textFieldAtIndex:0];
textField.placeholder = NSLocalizedString(#"Title", #"placeholder text where user enters name for new playlist");
textField.delegate = self;
[_query show];
}
After UIAlertView is shown, keyboard is shown too and UITextfield is focus (It just works on pre iOS7, but does not work in iOS8). I have tried [textfield becomeFirstResponder], but it does not worked. I create new project and use cove above, it works.
My problem: Keyboard does not shown with UIAlertViewStylePlainTextInput style.
I don't know why? Can anybody helps me?
Thanks.
Here's a slight improvement to Chen Lim's hack/fix, to be placed in the UIAlertViewDelegate:
- (void)didPresentAlertView:(UIAlertView *)alertView {
if (isIOS8) {
// hack alert: fix bug in iOS 8 that prevents text field from appearing
UITextRange *textRange = [[alertView textFieldAtIndex:0] selectedTextRange];
[[alertView textFieldAtIndex:0] selectAll:nil];
[[alertView textFieldAtIndex:0] setSelectedTextRange:textRange];
}
}
(You'll have to implement an isIOS8 method, property, or iVar.)
This ugly hack worked for me, after calling show:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// HACKHACK: This is to make the keyboard appear in iOS8
UITextRange* textRange = self.textField.selectedTextRange;
[self.textField selectAll:self];
[UIMenuController sharedMenuController].menuVisible = NO;
self.textField.selectedTextRange = textRange;
});
Ran into the same problem, and spent hours fiddling with UIAlertController, which is the "right" solution, but unfortunately has several issues elsewhere (e.g. it breaks when presenting from a popover), and won't work with iOS7.
This is definitely a bug in iOS8. I hope Apple fixes this soon. It unfortunately breaks even with older binaries compiled for iOS7.
This helps me to fix all related issues:
[MyUITextView endEditing:YES];
Put it before showing UIAlertView.
In my case this was happening because the UIViewController that was presenting the UIAlertView had implemented canBecomeFirstResponder with a YES result since I wanted to listen for 'shake' events.
Once I added the following implementation of the UIAlertViewDelegate method the keyboard was presented as expected:
- (void)willPresentAlertView:(UIAlertView *)alertView
{
[self resignFirstResponder];
}
So this may not solve all of the problems with this so-called 'deprecated' class but it is something to check if your controller is enabling first-responder behaviour.
For me the issue was that a text field already had first responder status, so the keyboard was already visible when the alert code was invoked. Dismissing this field fixed the issue.
Are you seeing this on a device, or just in the sim?
There appears to be an issue with the iOS8 sim where it detects a physical keyboard, and doesn't show the software keyboard. Could possibly be intentional, as you technically are using a physical keyboard...it's just not the ideal behavior for sim testing.
Try command K to toggle the software keyboard in the sim if that's your issue.
I came cross with the same situation,and how I solved this bug is trying to resign current responder before showing the alertView.And UITextField's keyboard is popping up as expected.
UITextField *textField = ...; // Suppose textField is currently being edited.
[textField resignFirstResponder]; // before showing,resign first.
[_query show];
The first page of the UIAlertView documentation states:
Subclassing Notes
The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this
class is private and must not be modified.
For more information about appearance and behavior configuration, see
“Alert Views”.
In other words, you shouldn't be messing around with the contents of UIAlertView window. The fact it actually works in earlier OS versions than iOS 8 is just a bonus. It's deprecated as of iOS 8.
What you'll want to do in iOS 8 is make use of the brand new UIAlertController class, which does allow editable text fields.
I'm a bit new to iOS development, and right now am working on some simple UI-related stuff. I have a UIAlertView that I'm using at one point to allow the user to enter some text, with simple Cancel and OK buttons. The OK button should be disabled if the text field is blank.
I added to my UIAlertViewDelegate an alertViewShouldEnableFirstOtherButton function, so the OK button would disable when there's no text, and I also set the UIAlertView's UITextField to have clearOnBeginEditing true, so the previous text would be gone every time I displayed the alert. Each of these things works perfectly on their own. Unfortunately, it seems like the AlertView is checking whether or not to enable the OK button before the text field is cleared, so when they're put together it comes up enabled. Below should be about the minimal code needed to reproduce.
-(void)viewDidLoad
{
textEntryBox = [[UIAlertView alloc] initWithTitle:#"Name" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[textEntryBox setAlertViewStyle:UIAlertViewStylePlainTextInput];
[textEntryBox textFieldAtIndex:0].clearsOnBeginEditing = YES;
}
-(IBAction)functionTriggeredByOtherLogic
{
[textEntryBox show];
}
-(BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
if(alertView == textEntryBox)
{
if([[alertView textFieldAtIndex:0].text length] > 0)
{
return YES;
}
else
{
return NO;
}
}
return YES;
}
So, ultimately, my question is this: am I doing something completely against the natural iOS way of doing things here? Is there a better way to do this? Should I just ignore the clearsOnBeginEditing property of the UITextField, and manually clear the Text property before showing the UIAlertView?
Try to set the textfield delegate to self
[[textEntryBox textFieldAtIndex:0] setDelegate:self]
and implement this method :
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[textField setText:#""];
}
I'm also having a UIAlertView with a textField to fill-in in my app, and it works for me
Using an alert view for this is probably a bit much. It might be easier if you use the master-detail paradigm and just push a new view controller where you can enter your values.
I have a UITextfield that i'd like to dismiss the keyboard for. I can't seem to make the keyboard go away no matter what code i use.
If you have multiple text fields and don't know which one is first responder (or you simply don't have access to the text fields from wherever you are writing this code) you can call endEditing: on the parent view containing the text fields.
In a view controller's method, it would look like this:
[self.view endEditing:YES];
The parameter forces the text field to resign first responder status. If you were using a delegate to perform validation and wanted to stop everything until the text field's contents were valid, you could also code it like this:
BOOL didEndEditing = [self.view endEditing:NO];
if (didEndEditing) {
// on to the next thing...
} else {
// text field must have said to first responder status: "never wanna give you up, never wanna let you down"
}
The endEditing: method is much better than telling individual text fields to resignFirstResponder, but for some reason I never even found out about it until recently.
[myTextField resignFirstResponder]
Here, second paragraph in the Showing and Hiding the Keyboard section.
I've discovered a case where endEditing and resignFirstResponder fail. This has worked for me in those cases.
ObjC
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
[self setEditing:NO];
Swift
UIApplication.shared.sendAction(#selector(resignFirstResponder), to: nil, from: nil, for: nil)
There are cases where no text field is the first responder but the keyboard is on screen.
In these cases, the above methods fail to dismiss the keyboard.
One example of how to get there:
push the ABPersonViewController on screen programmatically; open any contact;
touch the "note" field (which becomes first responder and fires up the keyboard);
swipe left on any other field to make the "delete" button appear;
by this point you have no first responder among the text fields (just check programmatically) but the keyboard is still there. Calling [view endEditing:YES] does nothing.
In this case you also need to ask the view controller to exit the editing mode:
[viewController setEditing:NO animated:YES];
I suggest you add and action on your header file:
-(IBAction)removeKeyboard;
And in the implementation, write something like this:
-(IBAction)removeKeyboard
{
[self.textfield resignFirstResponder];
}
In the NIB file, connect from the UITextFiled to the File's Owner on the option DidEndOnExit. That way, when you press return, the keyboard will disappear.
Hope it helps!
In your view controller YourViewController.h file, make sure you implement UITextFieldDelegate protocol :
#interface YourViewController : <UITextFieldDelegate>
#end
Then, in YourViewController.m file, implement the following instance method:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.yourTextField1 resignFirstResponder];
[self.yourTextField2 resignFirstResponder];
...
[self.yourTextFieldn resignFirstResponder];
}
To resign any text field in the app
UIApplication.shared.keyWindow?.endEditing(true)
This approach is clean and guarantied to work because the keyWindow is, by definition, the root view of all possible views displaying a keyboard (source):
The key window receives keyboard and other non-touch related events. Only one window at a time may be the key window.
This will resign one particular text field
// Swift
TextField.resignFirstResponder()
// Objective C
[TextField resignFirstResponder];
To resign any text field use below code
// Swift
self.view!.endEditing(true)
// Objective C
[self.view endEditing:YES];
as a last resort 💩
let dummyTextView = UITextView(frame: .zero)
view.addSubview(dummyTextView)
dummyTextView.becomeFirstResponder()
dummyTextView.resignFirstResponder()
dummyTextView.removeFromSuperview()
If you don't know which textField is the first responder you can find it. I use this function:
UIView *resignFirstResponder(UIView *theView)
{
if([theView isFirstResponder])
{
[theView resignFirstResponder];
return theView;
}
for(UIView *subview in theView.subviews)
{
UIView *result = resignFirstResponder(subview);
if(result) return result;
}
return nil;
}
Then in your code call:
UIView *resigned = resignFirstResponder([UIScreen mainScreen]);
You just replace yourTextFieldName with, you guessed it! your textfield. This will close the keyboard.
[yourTextFieldName resignFirstResponder];
-(void)methodName
{
[textFieldName resignFirstResponder];
}
call this method (methodName) with didEndOnExit
For Swift 3
You can hide the keyboard like this:
textField.resignFirstResponder()
If you want to hide the keyboard when the user press the "intro" button, you have to implement the following UITextFieldDelegate method:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
// your code
[textField reloadInputViews];
}
3 Simple & Swift steps
Add UITextFieldDelegate to your class as below:
class RegisterVC: UIViewController, UITextFieldDelegate {
//class implementation
}
in class implementation, add the delegate function textFieldShouldEndEditing::
internal func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return true
}
and as a last step, set your UITextField(s) delegate(s) to self, in somewhere appropriate. For example, inside the viewDidLoad function:
override func viewDidLoad(){
super.viewDidLoad()
myTextField1.delegate = self
myTextField2.delegate = self
..
..
}
Now, whenever user hits the return key, keyboard will dismiss.
I prepared an example snippet too, you can check it from here.
Set up the "Did End On Exit" event in Xcode (right click on your text field).
Realize this method:
-(IBAction) closeKeyboard:(id) sender {
[_txtField resignFirstResponder];
}