Anilkumar iOS Developer
Anilkumar iOS Developer

Reputation: 3755

AutoComplete for UITextfield in iOS

I am working on new iOS application. In that app, I have 5 UITextFields and those are 1. first interest, second interest upto 5 interests.

I need to add Autocomplete for those 5 UITextFields. I have searched google for one day. I got some forums and tutorial for that. But I even have tried with Github links also.

According to my requirement, I have an array of data which is getting from my server. In that array, I have data like, coffee, cricket, etc. That is Autocomplete data. I need to display that array whenever user entered text in UITextField, if its related to my array of data, need to display below of that UITextFields.

For that purpose i used following code.

**// String in Search textfield

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

**

// Take string from Search Textfield and compare it with autocomplete array

- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {

// Put anything that starts with this substring into the autoCompleteArray
// The items in this array is what will show up in the table view

[autoCompleteArray removeAllObjects];
NSLog(@"autoCompleteArray %@",autoCompleteArray);
for(NSString *curString in elementArray) {
    NSRange substringRangeLowerCase = [curString rangeOfString:[substring lowercaseString]];
    NSRange substringRangeUpperCase = [curString rangeOfString:[substring uppercaseString]];

    if (substringRangeLowerCase.length != 0 || substringRangeUpperCase.length != 0) {
        [autoCompleteArray addObject:curString];
    }
}

autoCompleteTableView.hidden = NO;
[autoCompleteTableView reloadData];
      }

And I created UITableView as AutocompleteTableview in ViewDidLoad method.

**Issue is, if I type text as suppose "c", from my array of data displaying whatever text contains as "c" letter in tableview. But, if i typed "coff" no data displaying in that UITableView. Also how to validate which UITextField user clicking in tableviewdidselectrowatindexpath delegate method. I tried with assigning tag for those UITextFields, but its working in UITextFields delegate methods only, not in other place. so, whenever i selected data from UITableView, first UITextField only taking data not other UITextField.

Please give your valuable suggestion, which is the best way to display the autocomplete for UITextfields in iOS for multiple UITextfields and how to handle UITableView for displaying data. If anything mistakes in my content forgive me and please provide your valuable suggestions to fix this issue.

Thanks****

Upvotes: 2

Views: 18237

Answers (4)

Enamul Haque
Enamul Haque

Reputation: 5063

Here is swift 3 inline autocomplete textfield example

  1. Image look like bellow enter image description here

  2. create a project & add a textfield. Connect to viewcontroller named txtAutoComplete

  3. View controller code bellow

     import UIKit
    
       class ViewController: UIViewController ,UITextFieldDelegate{
    
    
        @IBOutlet weak var txtAutoComplete: UITextField!
    
         var autoCompletionPossibilities = ["01921687433", "01553377642", "0155776622"]
        var autoCompleteCharacterCount = 0
       var timer = Timer()
    
    
      override func viewDidLoad() {
         super.viewDidLoad()
    
    
          txtAutoComplete.delegate = self
     }
    
    
    
    
    
       func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { //1
           var subString = (textField.text!.capitalized as NSString).replacingCharacters(in: range, with: string) 
    subString = formatSubstring(subString: subString)
    
       if subString.characters.count == 0 { 
       // 3 when a user clears the textField
        resetValues()
           } else {
         searchAutocompleteEntriesWIthSubstring(substring: subString)   
        }
       return true
      }
    
     func formatSubstring(subString: String) -> String {
        let formatted = String(subString.characters.dropLast(autoCompleteCharacterCount)).lowercased().capitalized //5
        return formatted
     }
    
    func resetValues() {
       autoCompleteCharacterCount = 0
       txtAutoComplete.text = ""
      }
    
      func searchAutocompleteEntriesWIthSubstring(substring: String) {
      let userQuery = substring
      let suggestions = getAutocompleteSuggestions(userText: substring) 
    
        if suggestions.count > 0 {
          timer = .scheduledTimer(withTimeInterval: 0.01, repeats: false, block: { (timer) in //2
            let autocompleteResult =   self.formatAutocompleteResult(substring: substring, possibleMatches: suggestions)
               self.putColourFormattedTextInTextField(autocompleteResult: autocompleteResult, userQuery : userQuery) 
              self.moveCaretToEndOfUserQueryPosition(userQuery: userQuery) 
          })
    
         } else {
           timer = .scheduledTimer(withTimeInterval: 0.01, repeats: false, block: { (timer) in //7
              self.txtAutoComplete.text = substring
           })
           autoCompleteCharacterCount = 0
         }
    
    }
    
     func getAutocompleteSuggestions(userText: String) -> [String]{
       var possibleMatches: [String] = []
       for item in autoCompletionPossibilities { //2
          let myString:NSString! = item as NSString
          let substringRange :NSRange! = myString.range(of: userText)
    
          if (substringRange.location == 0)
           {
              possibleMatches.append(item)
          }
       }
       return possibleMatches
    }
    
     func putColourFormattedTextInTextField(autocompleteResult: String, userQuery : String) {
          let colouredString: NSMutableAttributedString = NSMutableAttributedString(string: userQuery + autocompleteResult)
    colouredString.addAttribute(NSForegroundColorAttributeName, value: UIColor.green, range: NSRange(location: userQuery.characters.count,length:autocompleteResult.characters.count))
    self.txtAutoComplete.attributedText = colouredString
    }
    
     func moveCaretToEndOfUserQueryPosition(userQuery : String) {
        if let newPosition = self.txtAutoComplete.position(from: self.txtAutoComplete.beginningOfDocument, offset: userQuery.characters.count) {
        self.txtAutoComplete.selectedTextRange = self.txtAutoComplete.textRange(from: newPosition, to: newPosition)
    }
          let selectedRange: UITextRange? = txtAutoComplete.selectedTextRange
    txtAutoComplete.offset(from: txtAutoComplete.beginningOfDocument, to: (selectedRange?.start)!)
       }
    
     func formatAutocompleteResult(substring: String, possibleMatches: [String]) -> String {
         var autoCompleteResult = possibleMatches[0]
    autoCompleteResult.removeSubrange(autoCompleteResult.startIndex..<autoCompleteResult.index(autoCompleteResult.startIndex, offsetBy: substring.characters.count))
    autoCompleteCharacterCount = autoCompleteResult.characters.count
    return autoCompleteResult
        }
      }
    
  4. Source code is given to GitHub.GitHub Link :https://github.com/enamul95/AutoCompleteTextField

Upvotes: 3

Maul
Maul

Reputation: 1179

Take two Global Array

NSMutableArray *muary_Interest_Main;
NSMutableArray *muary_Interest_Sub;

IN viewDidLoad Method

muary_Interest_Main = [[NSMutableArray alloc]initWithObjects:@"Cricket",@"Dancing",@"Painting",@"Swiming",@"guitar",@"movie",@"boxing",@"drum",@"hockey",@"chessing",@"gamming", 
    @"hunting",@"killing",@"shoping",@"jamm"@"zooming", nil]; 
muary_Interest_Sub = [[NSMutableArray alloc]init]; 


tbl_Search = [[UITableView alloc] initWithFrame: 
CGRectMake(4, 200, 320, 120) style:UITableViewStylePlain]; 
tbl_Search.delegate = self; 
tbl_Search.dataSource = self; 
tbl_Search.scrollEnabled = YES; 

[self.tbl_Search registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CellIdentifier"]; 
[self.view addSubview:self.tbl_Search]; 


[tbl_Search setHidden:TRUE];

Now write a below code in textfield delegates.

- (void)textFieldDidBeginEditing:(UITextField *)textField 
{ 
NSLog(@"%d",textField.tag); 
int_TextFieldTag = textField.tag; 

[self searchText:textField replacementString:@"Begin"]; 
} 

- (BOOL)textFieldShouldReturn:(UITextField *)textField { 
[textField resignFirstResponder]; 
tbl_Search.hidden = TRUE; 
return YES; 
} 

- (void)textFieldDidEndEditing:(UITextField *)textField 
{ 
tbl_Search.hidden = TRUE; 
} 

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 
{ 
[self searchText:textField replacementString:string]; 
return YES; 
}

Write a method for search text

-(void) searchText:(UITextField *)textField replacementString:(NSString *)string
{

    if(int_TextFieldTag == 1)
    {
        tbl_Search.frame = CGRectMake(4, 200, 320, 120);

    }
    else if(int_TextFieldTag == 2)
    {
        tbl_Search.frame = CGRectMake(4, 248, 320, 120);
    }
    else if(int_TextFieldTag == 3)
    {
        tbl_Search.frame = CGRectMake(4, 268, 320, 120);
    }
    else if(int_TextFieldTag == 4)
    {
        tbl_Search.frame = CGRectMake(4, 268, 320, 120);
    }
    else
    {
        tbl_Search.frame = CGRectMake(4, 268, 320, 120);
    }



    NSString *str_Search_String=[NSString stringWithFormat:@"%@",textField.text];
    if([string isEqualToString:@"Begin"])
        str_Search_String=[NSString stringWithFormat:@"%@",textField.text];
    else if([string isEqualToString:@""])
        str_Search_String = [str_Search_String substringToIndex:[str_Search_String length] - 1];
    else
        str_Search_String=[str_Search_String stringByAppendingString:string];

    muary_Interest_Sub=[[NSMutableArray alloc] init];
    if(str_Search_String.length>0)
    {
        NSInteger counter = 0;
        for(NSString *name in muary_Interest_Main)
        {
            NSRange r = [name rangeOfString:str_Search_String options:NSCaseInsensitiveSearch];
            if(r.length>0)
            {
                [muary_Interest_Sub addObject:name];
            }

            counter++;

        }

        if (muary_Interest_Sub.count > 0)
        {
            NSLog(@"%@",muary_Interest_Sub);
            tbl_Search.hidden = FALSE;
            [self.tbl_Search reloadData];
        }
        else
        {
           tbl_Search.hidden = TRUE;
        }



    }
    else
    {
        [tbl_Search setHidden:TRUE];

    }

}

Tableview Delegates methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
return [muary_Interest_Sub count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"]; 
if (cell == nil) 
{ 
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"CellIdentifier"]; 
//cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
; 
} 
cell.textLabel.text = [muary_Interest_Sub objectAtIndex:indexPath.row]; 
return cell; 

} 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
[self.view endEditing:YES]; 
if(int_TextFieldTag == 1) 
{ 
txt1.text=[muary_Interest_Sub objectAtIndex:indexPath.row]; 

} 
else if(int_TextFieldTag == 2) 
{ 
txt2.text=[muary_Interest_Sub objectAtIndex:indexPath.row]; 
} 
else if(int_TextFieldTag == 3) 
{ 
txt3.text=[muary_Interest_Sub objectAtIndex:indexPath.row]; 
} 
else if(int_TextFieldTag == 4) 
{ 
txt4.text=[muary_Interest_Sub objectAtIndex:indexPath.row]; 
} 
else 
{ 
txt5.text=[muary_Interest_Sub objectAtIndex:indexPath.row]; 
} 

} 

This also works on backspace of textfield. Try this. Hope this will suit your requirements.

Upvotes: 2

Harshini Nerella
Harshini Nerella

Reputation: 99

- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring{

    //Assume this array is the autocomplete array for which you get data from server

    NSMutableArray *autoCompleteArray = [[NSMutableArray alloc] initWithObjects:@"Coffee",@"Cricket",@"Volleyboll",nil];

    text = [text stringByReplacingOccurrencesOfString:@" " withString:@""];

   // This is to create predicate filter for getting matched text 

   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] %@",text];

// store matched data for autocompletion in results array and reload data in your tableview based on this array's data

   NSArray *resultArray = [[NSArray alloc] initWithArray:[autoCompleteArray filteredArrayUsingPredicate:predicate]];
}

Upvotes: 2

Joemon Johny
Joemon Johny

Reputation: 56

You can use the following links which describes how we can use autocompletion. I tried with the AutocompletionTableview (second link) and it worked perfectly.

https://github.com/EddyBorja/MLPAutoCompleteTextField

https://github.com/keyf/AutocompletionTableView

Upvotes: 0

Related Questions