I want my Keyboard to change from UIKeyboardTypeNumbersAndPunctuation mode to normal text mode after the user hits space.
So he can easily type something like "34 loops".
Okay, you cannot get direct input notifications, but there's a solution I can think of.
Implement the following delegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
The replacement string will, as its name states, contain the string that wants to replace the existing string in the text field. What you could do is check the last character of this string, and if it is indeed a space, then change the keyboard type:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
char lastCharacter = [string characterAtIndex:[string length] - 1]; //Get the last input character in the ext field.
if(lastCharacter == ' ')
{
//The last character is a space, so...
textField.keyboardType = UIKeyboardTypeDefault;
[textField resignFirstResponder];
[textField becomeFirstResponder];
}
return YES;
}
The answer given by Leonnears mostly answers the simple case, but there are many issues you need to consider. What happens if the user types 34, then a space, then delete? What happens when the user moves the caret from the end of loops to somewhere in the number part?
It all starts to get more difficult to cover each case. But more importantly, it starts to get annoying for the user as the keyboard starts changing on them. It makes it very difficult to just type in the text. I've never seen an app do what you propose and there is a good reason.
Let the user use the normal keyboard like they are used to. Everyone knows how to switch between letter and numbers. Having the keyboard automatically change will be unusual and confusing.
Related
I have this code that should catch exactly what the user types:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSLog(#"Catch -> %#",textfield.text);
}
But When the user digit the letter A, the console return me ('null'), When the user digit the letter AB, the console return me only the letter A, in this case the method shouldChangeCharactersInRange doesn't return the last letter that user types.
To change this I try to change my code to:
NSLog(#"Catch -> %#",string);
In this case, the console shows me only the last number. How can I solve this problem and pick the complete sentence that user digit?
This method is called BEFORE the text field has changed. If you speak English, you would have already known this just by reading the method name, one of the big advantages of Cocoa...
This method gives you a chance to say "NO, don't change the text in this text box!" or to change the text in the box before the change is made, or to change the text that will be added before it's added.
textfield.text won't reflect the change until after this method returns.
To catch the END of editing events for a textfield, put this in your viewDidLoad:
[yourTextField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
Where yourTextField is a reference to the text field of interest.
Now write the method:
- (void)textFieldDidChange:(UITextfield *)textfield {
NSLog(#"Catch -> %#", textfield.text);
}
This delegate method for me usually starts out like this:
- (BOOL)textField:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
NSString *candidateString = [textView.text stringByReplacingCharactersInRange:range withString:text];
Now, candidateString will contain what you expect. It's done this way so that any manner of input (even a paste into the middle of the text) can be understood before and after the text field's text is updated
I have looked around for ways to detect when the delete key is pressed. I came across Apple's key handling documentation and also some people trying this with work arounds. I am not sure which method to pursue. What I want to do is very simple:
-(void)deleteKeyWasPressed {
if (myTextField.text.length == 0) {
[previousTextField becomeFirstResponder];
}
}
But as far as I know this method does not exist.
What would be the best way of doing this?
iOS has no direct support for detecting the delete key (or any key other than Return). The best you can do is implement the textField:shouldChangeCharactersInRange:replacementString: delegate method. When the user taps the Delete key, the replacement string will be the empty string.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (string.length == 0) {
// handle Delete (but this also handles the Cut menu as well)
} else {
// some other key or text is being pasted.
}
return YES;
}
The way that I have implemented it is to save the previous length of the textfield somewhere, and then compare the previous length to the current length. If the previous length is greater than the current length, then the delete key was pressed. Works well for me.
I'm trying to implement a program in Xcode that's somewhat like a command line. I basically have a UITextView that can take multiple lines of text. Right now, I have a button that will make the necessary changes after the user is done entering commands, but I want to be able to have a method that gets called after the user hits the return key in the UITextView, so basically it makes changes after each command. Is it possible to do this?
The BOOL method mentioned above is a wrong answer... for one the person is checking the text from the TextView the moment before it is updated so they are viewing the old text... Also the methods are out of date.
This usage will work immediately once the return key is pressed (The current "answer" will not work until after the return key has been pressed and then ANOTHER key is pressed):
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([text isEqualToString:#"\n"]) {
NSLog(#"Return pressed");
} else {
NSLog(#"Other pressed");
}
return YES;
}
Don't forget to add the UITextViewDelegate to your .h file's protocols.
#interface ViewController : UIViewController <UITextViewDelegate> {
and set yourTextView.delegate = self; in .m file!
/*
note: This will also get called if a user copy-pastes just a line-break...
unlikely but possible. If you need to ignore pasted line-breaks for some
reason see here: http://stackoverflow.com/a/15933860/2057171 ...
Now for an unrelated-tip: If you want to accept pasted line breaks however
I suggest you add an "or" to the conditional statement and make it also
check if "text" isEqualToString #"\r" which is another form of line-break
not found on the iOS keyboard but it can, however, be found on a website
and copy-pasted into your textView. If you want to accept pasted text
with a line-break at the end you will need to change the
"isEqualToString" code above to say "hasSuffix", this will check for
any string %# with a "\n" at the end. (and again for "\r") but make
sure you don't call your "next" method until after `return YES;`
has been called and the text view has been updated, otherwise
you will get only the text that was there before the copy paste
since this is "shouldChangeTextInRange" method, not
"didChangeTextInRange", if you do this I suggest stripping the
"\n" or "\r" from the end of your final string after the copy-paste
was made and applied and the text was updated.
*/
If you set a delegate to the UITextView which implements
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
Then you can check if the last character is "\n", and get the text entered since the last command by doing
NSArray* components = [textView.text componentsSeparatedByString:#"\n"];
if ([components count] > 0) {
NSString* commandText = [components lastObject];
// and optionally clear the text view and hide the keyboard...
textView.text = #"";
[textView resignFirstResponder];
}
Note, I haven't tested this, just an idea:
- (void)textViewDidChange:(UITextView *)textView
{
if ([[textView.text substringWithRange:NSMakeRange(textView.text.length - 1, 1)] isEqualToString:#"\n"])
{
[textView resignFirstResponder];
[self methodYouWantToCall];
}
}
You can do this by setting up a delegate for the UITextView. See UITextViewDelegate Protocol Reference for details on what can be done.
I am having a problem finding the length of a text field's text!
I searched here a lot and just found that it would work with textfield.text.length or something like that.
My problem is textfield.text is not working for me!
If I write this code: textfield.text; then I get an error like this:
property "text" not found on object of type NSTextField
I have to find the length of an text field in order to limit the number of characters.
What should I do? Thanks in advance.
Most of the classes in AppKit, as opposed to UIKit, don't have properties. NSTextField doesn't even have a method called text. You need the stringValue method, which is inherited from NSControl
The generally accepted way of doing this (limiting the length of NSTextField) is by using the NSFormatter helper class. See Here
To limit the length you add the delegate methods to your controller by adding
< UITextFieldDelegate >
in the header file. Then in the implementation add the following method:
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
In here just check the length and either return the string or just the string length you want.
You can get the length with:
[[textfield stringValue] length]
In interface builder be sure and add the file owner as the delegate to the text field
I've been trying to learn to use Xcode, but I'm getting confused with how to register that NSTextField has changed. Essentially, I have an NSTextField and a button. Clicking the button does stuff with the text in the field. However, I want to be able to get the text of the field without needing to use the text field "Action:send on end editing." That is, I want to be able to enter text and immediately press the button, without hitting enter or tabbing out of the text box. It seems like the way to do this would be by setting a delegate for my NSTextField that responds to
- (void)controlTextDidChange:(NSNotification *)aNotification
But I don't understand how to get the text that has been entered. I assume it has something to do with
[[aNotification userInfo] valueForKey:#"NSFieldEditor"];
but I really have no idea where to go from there.
You're on the right track! The object that you get out of the notification's user info dictionary is the Field Editor, which is simply an NSTextView that's handling the text input on the text field's behalf.
Once you have that object, all you have to do is ask it for its textStorage, which is an NSTextStorage* object holding the text. That object, in turn, has its string which is a plain old NSString holding just the characters.
NSTextView * fieldEditor = [[aNotification userInfo] objectForKey:#"NSFieldEditor"];
NSString * theString = [[fieldEditor textStorage] string];
*A subclass of NSAttributedString, which is an object holding a string and associated "attributes" like color, font, and underlining.
In your button action method, simply read the current string value in the text field:
- (IBAction)didClickTheButton:(id)sender {
NSString* theString = [myTextField stringValue];
// do something with theString
}
If you're only ever handling a single text field, this may be simpler:
- (void)controlTextDidChange:(NSNotification *)obj {
[self.inputField stringValue];
}
I'm totally ignoring all the complicated details of NSText and whatnot and just using the simplicity of the notification being sent and the simplicity of getting the string value from a text field.