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
Related
I have an NSComboBox containing several items. If the user types while the list is open, I would like to select the appropriate item within the list (if there is a corresponding item).
The twist: The string in the text field is not necessarily equal to the corresponding item in the list. (The strings within the list may e.g. contain additional explanations.)
I tried implementing textDidChange:
- (void)textDidChange:(NSNotification *)notification {
NSString* nsstring = [self stringValue];
[self selectItemAtIndex: [self findCorrespondingIndex: nsstring]]; // changes text - even if documentation states that it "does not alter the contents of the combo box’s text field"
}
But, contrary to the documentation, selectItemAtIndex changes the text in the text field, so I tried the following:
- (void)textDidChange:(NSNotification *)notification {
NSString* nsstring = [self stringValue];
[self selectItemAtIndex: [self findCorrespondingIndex: nsstring]]; // changes text - even if documentation states that it "does not alter the contents of the combo box’s text field"
[self setStringValue:nsstring]; // clears selection
}
But, contrary to the documentation, setStringValue clears the selection.
Is this behavior expected?
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.
I found this perfect answer to search through an NSFetchedResultsController : https://stackoverflow.com/a/4481896/1486928
EDIT : project showing the issue : http://cl.ly/2x0C0N0E4240
It seems really great except it wasn't written to use with ARC, I tried to just remove all the "retain" "release" "autorelease".
It still works, well mostly, the thing is, when I enter a char in the searchbar it shows the filtered table as expected but it only takes 1 char (if you add more it doesn't do anything) and after that every other "search" will show the results of the first search that only took 1 char.
I've been at it for 2 days putting NSlog anywhere to see when every methods are called but still couldn't find how to make it work :(
Thanks !
Edit : here is .m http://pastebin.com/9U4TfbA6
Edit : here is .h http://pastebin.com/S9aaNRFE
Also if it can help the search works when I comment this :
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_! = nil)
{
return fetchedResultsController_;
}
...
}
And this :
- (NSFetchedResultsController *)searchFetchedResultsController {
if (searchFetchedResultsController_ != nil)
{
return searchFetchedResultsController_;
}
...
}
But it mess up other things :/
I guess that you are messing up with the search display controller delegate methods,
and especially you need to check this method
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString;
Because this method will reload your table view for every character which you type in your search field as the name itself suggests shouldReloadTableForSearchString
Edit:
Well you need to implement 2 delegate methods of UISearchBar because all your UISearchDisplayController delegate methods are same and those 2 methods are
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText;
This tells the delegate that the user changed the search text.
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
This is used if the text in a specified range should be replaced with given text.
and please note these methods are called several times, i mean for the every character added and deleted in the search bar and because you are setting the searchFetchedResultsController to nil every time the search text changes
just comment out this part, it will work well
/*if (searchFetchedResultsController_ != nil)
{
NSLog(#"Returned !nil searchController");
return searchFetchedResultsController_;
}*/
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'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.