I am trying to figure out if there is a way to implement an autocomplete functionality in a UITextField for specific values.
I know that the UITextField can do this using the iPhone dictionary (much like searching google in safari, etc), but I want to be able to programmatically have it correct to certain values that I specify.
How to do this?
I did something very similar to this while working on a recent and rather large project. We had a constantly changing list of auto complete terms and built an auto-complete around them.
First, you'll want to make some type of auto-complete controller. It should take a string and return all possible auto complete terms for that string.
-(NSArray *)completionsForString:(NSString *)myString;
Then, check out the UIMenuController class. It's the class that shows the cut/copy/paste options in many applications. You can get the shared instance of it, populate the menu items yourself, and show it above the text field. The user can then simply tap the term they want.
In the end, the solution worked really well for our needs.
Alternatively, you can use this UITextField subclass (inspired by DOAutocompleteTextField):
https://github.com/hoteltonight/HTAutocompleteTextField
It's got a few more features and is actively developed. The example shows you how to use an array as the data source for the autosuggest text. It takes the same approach as DOAutocompleteTextField, in that it shows the suggested completion text "ghosted" in the text field as the user types.
Have you looked into UISearchDisplayController? There are a few threads here on Stack Overflow, including Core Data references if that is what you are using. Also some alternative methods, elsewhere.
With the help of the aforementioned Ray Wenderlich tutorial, I just implemented a version of this to filter names in an existing UITableView.
I set my text field's delegate as my view controller, my view controller as a UITextFieldDelegate and implemented these two methods:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
}
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring
{
NSMutableArray *autoCompleteArray = [[NSMutableArray alloc]init];
[self retrieveData];
for(NSString *curString in _staffTableArray)
{
NSString *lowerCaseCur = [curString lowercaseString];
NSRange substringRange = [lowerCaseCur rangeOfString:substring];
if (substringRange.location == 0)
{
[autoCompleteArray addObject:curString];
}
}
if (![substring isEqualToString:#""])
{
_staffTableArray = [NSMutableArray arrayWithArray:autoCompleteArray];
}
[_staffListTableView reloadData];
}
use this delegate method. you can replace values that you specify.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
if ([string isEqualToString:#"StackO"]) {
textField.text=#"StackOverflow";
}
return YES;
}
Just faced with this thread because I need something similar. How about implementing you own search with the UITextfieldDelegate's method:
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
As you'd probably know this method is called for every UITextfield's typing.
Related
I am trying to implement a textView in which when user starts typing(Let's say names) it would show up the suggestions and when they click them it gets added to the textView than user presses comma and again the same functionality for another name....
And at the end the text in the textView should look like this...
Aron,Maria,Alex,Cassie
Can any one suggest me How can I achieve this?
(Its somewhat similar to adding the "Tags" while posting this question!!!)
Thanks.
You can use a NSTokenField replacement there is some libraries here :
tokenField libraries
Following link may help you:
http://www.raywenderlich.com/336/how-to-auto-complete-with-custom-values
Follow the same flow. To get autocomplete suggestions after comma modify the delegate method as found below.
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
autocompleteTableView.hidden = NO;
NSString *names = [NSString stringWithString:textField.text];
NSArray* arr = [names componentsSeparatedByString:#","];
NSString *subString = [arr lastObject];
substring = [substring
stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
}
Provide a NSMutableArray named 'allNames' which contains all the names you want to display in the suggestion list and use it as the following:
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {
[autocompleteUrls removeAllObjects];
for(NSString *curString in allNames) {
NSRange substringRange = [curString rangeOfString:substring];
if (substringRange.location == 0) {
[autocompleteUrls addObject:curString];
}
}
[autocompleteTableView reloadData];
}
When the user clicks the suggestions display the name by appending with previously entered names.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// set the textField.text by appending this name to already entered names
}
I didn't see anything like this in mobile app. You can look for libraries. But if you want to make it yourself I would advice you to use invisible tableView. When user starts typing name you should fetchData and show in tableView under textView. It's not hard.
A relatively easy way I can think of to achieve this functionality would be to add an input accessory view to your keyboard, which will offer suggestions.
You wouldn't have to tamper with the TextField itself, nor would you need to incorporate the suggestions into the remainder of your apps layout.
The accessory view could, for example, be given a reference to the textfield and listen to input by:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(textChanged) name:UITextFieldTextDidChangeNotification object:textFieldWithSuggestions];
It would feature a method -(void)textChanged; in which you would have the opportunity to split the existing text into components, using comma or whatever symbol as a separator, and then use the last text fragment to perform your search for possible completions.
It may present these suggestions as a row of buttons for example (maybe even in a side-scrolling scrollview to allow for many suggestions) and if one gets pushed, update the textfields text by replacing the last text segment with the completed string.
To keep track of which button stands for which suggestion, just give them tags according to the indices of your search results. This way, you'll need only one method as a target for the buttons, too.
If you want to some library code then you can go for this
https://github.com/hoteltonight/HTAutocompleteTextField which will help you
I want to set UILabel according to the UITextField as it is typed. I mean if user want to type SAMPLE and he starts typing S then the lable should be set as S, then he types A label should also be A and so on. How to achieve this?
Please share suggestions.
Thanks in advance
Simplest way to do is to make a method and connect it with UiTextfield with event UIControlEventEditingChanged which will give you the trace on every character entered in the textfield.
[self.selectedTextField addTarget:self action:#selector(enterInLabel ) forControlEvents:UIControlEventEditingChanged];
-(void)enterInLabel
{
selectedLabel.text=selectedTextField.text;
}
The delegate also works for this as #brain said. The shouldChangeCharactersInRange: method can be a little confusing but the the following I think is pretty straight forward.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// myTextField delegate has been set
if ([textField isEqual:myTextField]){
NSMutableString *txt = [NSMutableString stringWithString:textField.text];
[txt replaceCharactersInRange:range withString:string]; //this is essentially how the textfield is updated after YES is returned
previewLabel.text = txt;
}
return YES;
}
The changing of the text field is actually done after the return YES. That is the whole point of this delegate. Just for an example, if you wanted to limit a textfield to 3 characters you could do the following to stop the text field from "replacing" the text.
if (range.location > 3)
return NO;
Set your textField delegate then call its method in your viewController.m file.. like this -
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
mylabel.text = [textField.text stringByReplacingCharactersInRange:range withString:string];
return YES;
}
This will change the text after each increment of character.
OR You can add action on your TextField
See this link - UiTextField events
Your view controller will need to implement the UITextFieldDelegate which will allow it to receive changes to the text field. In the appropriate methods of the delegate you need to set the text of the UILabel.
I have never used UITextFieldDelegate so can't provide more detail on how to use it. I would mock up a quick example and just NSLog or debug the delegate calls to see that calls you get.
I have 10 textfields, in which I could enter only one character in each textfield. After a character is entered in each textfield, the focus should move to the next one. Similarly when i delete character from a textfield by pressing the backspace or delete, i need to get the focus to the previous textfield. If I could get the keypressed event, I could do that. Right now I am not able to find any keypressed event examples.
Implement UITextFieldDelegate.
Implement the delegate methods in the protocol. You can achieve the things you wanted.
You can set the focus by using the method becomeFirstResponder to the required textfield.
Have a look at the delegate method
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
The text field calls this method whenever the user types a new character in the text field or deletes an existing character.
So that could solve your problem.
Based on Aadhira's answer, but taking into account Kirk Woll's comment, you can generate what the latest text will be by using stringByReplacingCharactersInRange:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *value = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSLog(#"value: %#", value);
return YES;
}
Just to give you directions:
Assign tag to each text field.
Implement UITextFieldDelegate. There are all the methods you need to detect any event that takes place inside the text field. In each method you can check the tag and move focus properly.
Hint: you can use [mainView viewWithTag:XX] to quickly pick the text field you need.
Each time the text is changed you can check the text property of the text field and it will give you the answer which button was pressed.
you have to implement the UITextFieldDelegate protocol into your code and this method will tell you when you start begin editing in text field
– textFieldShouldBeginEditing:
and you can set the if condition in this method according to your requirement...
You have to use the textfieldDelegate methods.
In your textFieldShouldReturn method you have to set your responders like
if (textfield == textField1)
{
[textField2 becomeFirstResponder];
}
else if (textField == textField2)
{
[textField3 becomeFirstResponder];
}
else
{
[textField3 resignFirstResponder];
}
return YES; // as method return type is BOOL.
I have a UITextField in my application. I'd like to restrict the set of characters that can be can be entered into the field to a set that I have defined. I could filter the characters entered into the field when the text is committed using the UITextFieldDelegate method:
- (BOOL)textFieldShouldReturn:(UITextField*)textField
However, this gives the user a false impression as although restricted characters are removed from the final value, they were still visibly entered into the text field before pressing Return/Done/etc. What is the best approach that would prevent restricted characters appearing in the text field as they are selected on the keyboard?
Note: I am operating under the assumption that I have little control over which keys are provided by the iPhone keyboard(s). I am aware that I can switch between various keyboard implementations but am under the impression that I can't disable specific keys. This assumption may be incorrect.
I did as marcc suggested and it worked well. Sample implementation follows.
Note: Variable names were selected for brevity and do not reflect my coding standards:
...
myCharSet = [NSCharacterSet characterSetWithCharactersInString:#"xyzXYZ"];
...
}
- (BOOL) textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)textEntered {
for (int i = 0; i < [textEntered length]; i++) {
unichar c = [textEntered characterAtIndex:i];
if (![myCharSet characterIsMember:c]) {
return NO;
}
}
return YES;
}
Look at textField:shouldChangeCharactersInRange
This method is called by the UITextFieldDelegate whenever new characters are typed or existing characters are deleted from the text field. You could return NO to not allow the change.
Here is one of the cleanest approaches to restricting characters entered in a UITextField. This approach allows the use of multiple predefined NSCharacterSets.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet];
[allowedCharacters formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
[allowedCharacters formUnionWithCharacterSet:[NSCharacterSet symbolCharacterSet]];
if([string rangeOfCharacterFromSet:allowedCharacters.invertedSet].location == NSNotFound){
return YES;
}
return NO;
}
Look at the UITextViewDelegate method - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string.
It's exactly what you need.
This is what I use to restrict the user to uppercase A-Z. Adjust the regex variable according to taste:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* regex = #"[^A-Z]";
return ([string rangeOfString: regex
options:NSRegularExpressionSearch].location == NSNotFound);
};
How about this?
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* regex = #"[^a-z]";
return ([[string lowercaseString] rangeOfString: regex
options:NSRegularExpressionSearch].location == NSNotFound);
};
Note:
I am making all characters to lower case [string lowercaseString] so that you don't need to write in regex for captial/small letters.
You could loop and keep checking if the UITextField.text property has changed once the DidBeginEditing method gets called. If it has, check the text and remove an bad characters.
I've run into a problem with the UITextView that seems to be related to having a scrollable view within a scrollable view.
In order to remedy this i thought i would attempt to write my own multiline (but not scrollable) text view. Given the core graphics methods, and the UITextInputTraits class it seems like this should be feasable. The only thing i cant figure out is wether or not its possible to display (and catch events) for the system wide keyboard.
Is this even possible using the SDK?
What I did in a similar situation, is made a hidden UITextField, and set its delegate to your class where you can implement the appropriate UITextFieldDelegate methods to intercept the key's pressed.
something like this:
UITextField *myHiddenTextField = [[UITextField alloc] initWithFrame: cgRectZero()];
myHiddenTextField.delegate = self;
[myHiddenTextField becomeFirstResponder];
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
//use string here for the text input
return false;
}