I am using api. I post some data and store response in tableview. I put searchbar for search data from tableview. I want when I write 3 words in searchbar after that my api will call and data show in the tableview. I am using uitextfield for searchbar.
var array = [String]()
var tabledata = [String]()
var tableFilterData = [String]()
var isSearch :Bool!
let cellReuseIdentifier = "cell"
#IBOutlet weak var searchTextfield: UITextField!
#IBOutlet weak var tableview: UITableView!
#IBOutlet weak var heightConstraint: NSLayoutConstraint!
#IBAction func textfieldchanged(_ sender: Any) {
tableview.isHidden = true
}
override func viewDidLoad() {
super.viewDidLoad()
isSearch = false
self.apicalling()
searchTextfield.addTarget(self, action: #selector(textFieldActive), for: UIControlEvents.touchDown)
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
var searchText = textField.text! + string
if string == "" {
searchText = (searchText as String).substring(to: searchText.index(before: searchText.endIndex))
}
if searchText == "" {
isSearch = false
tableview.reloadData()
}
else{
getSearchArrayContains(searchText)
}
return true
}
func getSearchArrayContains(_ text : String) {
var predicate : NSPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", text)
tableFilterData = (tabledata as NSArray).filtered(using: predicate) as! [String]
isSearch = true
tableview.reloadData()
}
override func viewDidLayoutSubviews()
{
heightConstraint.constant = tableview.contentSize.height
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
guard let touch:UITouch = touches.first else
{
return;
}
if touch.view != tableview
{
searchTextfield.endEditing(true)
tableview.isHidden = true
}
}
#objc func textFieldActive() {
tableview.isHidden = !tableview.isHidden
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
my tableview part is this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearch! {
return tableFilterData.count
}
else{
return tabledata.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as UITableViewCell!
// Set text from the data model
if isSearch! {
cell.textLabel?.text = tableFilterData[indexPath.row]
cell.textLabel?.font = searchTextfield.font
}
else{
cell.textLabel?.text = tabledata[indexPath.row]
cell.textLabel?.font = searchTextfield.font
}
return cell
}
In my api calling my parameter is this
let param = ["var_name": "sha","API":"user_search","auth_token":authToken!]
but I want searchdata pass into the "var_name" .
my searchbar is working properly but I want when I write 3 words in searchbar after that api will call and that three data pass into the api as a parameters in "var_name".
I have created a simple autocomplete textfield (in which the autocomplete options are displayed in a tableview) through the following code:
import UIKit
class SchoolViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var schoolTextField: UITextField!
#IBOutlet weak var autoCompleteTableView: UITableView!
let schoolPossibilities = ["Redwood", "Fisher", "Bellermen", "Saratoga", "Los Gatos", "Cambell", "Mooreland", "Harker", "Challenger", "Saint Andrews", "Beckens", "Lynbrook", "Menlo", "Gunn", "Aragon", "Kipp"]
var autoCompleteSchools = [String]()
override func viewDidLoad() {
super.viewDidLoad()
autoCompleteTableView.delegate = self
schoolTextField.delegate = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "someCell", for: indexPath)
cell.textLabel?.text = autoCompleteSchools[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autoCompleteSchools.count
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let text = schoolTextField.text{
let substring = (text as NSString).replacingCharacters(in: range, with: string)
searchAutoCompleteEntries(withSubstring: substring)
}
return true
}
func searchAutoCompleteEntries(withSubstring substring: String){
autoCompleteSchools.removeAll()
for key in schoolPossibilities{
let string = key as NSString
let range = string.range(of: substring)
if range.location == 0{
autoCompleteSchools.append(key)
}
}
autoCompleteTableView.reloadData()
}
}
The problem is that options only show up if what's being typed in the textfield is an EXACT match. How do I change this code so it can tolerate both uppercase and lowercase letters and slight variations?
Use NSCaseInsensitiveSearch as compare option in
outputString.rangeOfString(String, options: NSStringCompareOptions, range: <#T##Range<Index>?#>, locale: <#T##NSLocale?#>)
I have a text field that, when you type a name, should show a suggested name that get I from an array with JSON, the problem is that it shows only one name. For example if I type Tom it shows only Tom Cruise and not Tommy Gien. How can I resolve that?
CODE:
class ViewController: UIViewController, UITextViewDelegate, UITextFieldDelegate,UITableViewDataSource, UITableViewDelegate {
let save = NSUserDefaults.standardUserDefaults()
#IBOutlet var amountPoints: UILabel!
#IBOutlet var reasonView: UITextView!
#IBOutlet var toField: UITextField!
#IBOutlet var pointsField: UITextField!
#IBOutlet var autocompleteTableView: UITableView!
var pastUrls: [String] = []
var autocompleteUrls = [String]()
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
toField.delegate = self
reasonView.layer.cornerRadius = 1
reasonView.layer.borderWidth = 0.7
reasonView.layer.borderColor = UIColor.grayColor().CGColor
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = true
getallUser()
var Names = save.arrayForKey("give.Name")
pastUrls = Names as! [String]
print(pastUrls)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
autocompleteTableView.hidden = false
let substring = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
searchAutocompleteEntriesWithSubstring(substring)
return true // not sure about this - could be false
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
let myString:NSString! = curString as NSString
let substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier, forIndexPath: indexPath) as UITableViewCell
let index = indexPath.row as Int
cell.textLabel!.text = autocompleteUrls[index]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
toField.text = selectedCell.textLabel!.text
autocompleteTableView.hidden = true
}
func textViewDidBeginEditing(textView: UITextView) {
reasonView.text = ""
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
if text == "\n"
{
textView.resignFirstResponder()
return false
}
return true
}
#IBAction func giveButton(sender: UIButton) {
}
#IBAction func returnButton(sender: UIBarButtonItem) {
self.dismissViewControllerAnimated(true, completion: nil)
}
Try replacing your method in seachAutocompleteEntriesWithSubtring with the following
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
var myString:NSString! = curString as NSString
var substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
After Successfully running the program the error will be shows on debug area
import UIKit
import CoreLocation
protocol ItemDetailViewControllerDelegate: class {
func itemDetailViewControllerDidCancel(controller: ItemDetailViewController)
func itemDetailViewController(controller: ItemDetailViewController, didFinishAddingItem item: NoToDoItem)
func itemDetailViewController(controller: ItemDetailViewController, didFinishEditingItem item: NoToDoItem)
}
class ItemDetailViewController: UITableViewController, CLLocationManagerDelegate {
#IBAction func myLocation(sender: AnyObject) {
self.LocationManager.delegate = self
self.LocationManager.desiredAccuracy = kCLLocationAccuracyBest
self.LocationManager.requestWhenInUseAuthorization()
self.LocationManager.startUpdatingLocation()
}
let LocationManager = CLLocationManager()
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var descriptionTextView: UITextView!
#IBOutlet weak var doneBarButton: UIBarButtonItem!
#IBOutlet weak var dueDateLabel: UILabel!
weak var delegate: ItemDetailViewControllerDelegate?
var itemToEdit: NoToDoItem?
var dueDate = NSDate()
var datePickerVisible = false
override func viewDidLoad() {
super.viewDidLoad()
if let item = itemToEdit {
title = "Edit Item"
textField.text = item.text
descriptionTextView.text = item.text
dueDate = item.dueDate
doneBarButton.enabled = true
}
updateDueDateLabel()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: { (placemarks, error) -> Void in
if (error != nil) {
print("Error")
return
}
if let pm = placemarks?.first
{
self.displayLocationInfo(pm)
}
else {
print("errorData")
}
})
}
func displayLocationInfo(placemark: CLPlacemark){
self.LocationManager.stopUpdatingLocation()
print(placemark.locality)
print(placemark.postalCode)
print(placemark.administrativeArea)
print(placemark.country)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error:" + error.localizedDescription)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
textField.becomeFirstResponder()
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let oldText: NSString = textField.text!
let newText: NSString = oldText.stringByReplacingCharactersInRange(range, withString: string)
doneBarButton.enabled = (newText.length > 0)
return true
}
#IBAction func done(sender: AnyObject) {
if let item = itemToEdit {
item.text = textField.text!
textField.becomeFirstResponder()
item.text = descriptionTextView.text!
descriptionTextView.becomeFirstResponder()
item.dueDate = dueDate
delegate?.itemDetailViewController(self, didFinishEditingItem: item)
} else {
let item = NoToDoItem()
item.text = textField.text!
item.dueDate = dueDate
delegate?.itemDetailViewController(self, didFinishAddingItem: item)
}
}
#IBAction func cancel(sender: AnyObject) {
delegate?.itemDetailViewControllerDidCancel(self)
}
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
if indexPath.section == 2 && indexPath.row == 1
{
return indexPath
} else {
return nil
}
}
func updateDueDateLabel() {
let formatter = NSDateFormatter()
formatter.dateStyle = .MediumStyle
formatter.timeStyle = .ShortStyle
dueDateLabel.text = formatter.stringFromDate(dueDate)
}
func showDatePicker() {
datePickerVisible = true
let indexPathDateRow = NSIndexPath(forRow: 1, inSection: 2)
let indexPathDatePicker = NSIndexPath(forRow: 2, inSection: 2)
if let dateCell = tableView.cellForRowAtIndexPath(indexPathDateRow)
{
dateCell.detailTextLabel!.textColor = dateCell.detailTextLabel!.tintColor
}
tableView.beginUpdates()
tableView.insertRowsAtIndexPaths([indexPathDatePicker],withRowAnimation: .Fade)
tableView.reloadRowsAtIndexPaths([indexPathDateRow], withRowAnimation: .None)
tableView.endUpdates()
if let pickerCell = tableView.cellForRowAtIndexPath( indexPathDatePicker) {
let datePicker = pickerCell.viewWithTag(100) as! UIDatePicker
datePicker.setDate(dueDate, animated: false)}
}
func hideDatePicker()
{
if datePickerVisible {
datePickerVisible = false
let indexPathDateRow = NSIndexPath(forRow: 1, inSection: 2)
let indexPathDatePicker = NSIndexPath(forRow: 2, inSection: 2)
if let cell = tableView.cellForRowAtIndexPath(indexPathDateRow) {
cell.detailTextLabel!.textColor = UIColor(white: 0, alpha: 0.5)
}
tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPathDateRow], withRowAnimation: .None)
tableView.deleteRowsAtIndexPaths([indexPathDatePicker], withRowAnimation: .Fade)
tableView.endUpdates()
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 2 && datePickerVisible { return 3
} else {
return super.tableView(tableView, numberOfRowsInSection: section)
}
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.section == 2 && indexPath.row == 2 {
return 217
} else {
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 1
if indexPath.section == 2 && indexPath.row == 2 { // 2
var cell: UITableViewCell! = tableView.dequeueReusableCellWithIdentifier("DatePickerCell")
if cell == nil {
cell = UITableViewCell(style: .Default,
reuseIdentifier: "DatePickerCell")
cell.selectionStyle = .None
// 3
let datePicker = UIDatePicker(frame: CGRect(x: 0, y: 0,
width: 320, height: 216))
datePicker.tag = 100
cell.contentView.addSubview(datePicker)
// 4
datePicker.addTarget(self, action: Selector("dateChanged:"), forControlEvents: .ValueChanged)
}
return cell
// 5
} else {
return super.tableView(tableView, cellForRowAtIndexPath: indexPath)
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool{
textField.resignFirstResponder()
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
hideDatePicker()
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)
textField.resignFirstResponder()
if indexPath.section == 2 && indexPath.row == 1 { if !datePickerVisible {
showDatePicker()
}
else
{
hideDatePicker()
}
}
}
override func tableView(tableView: UITableView, var indentationLevelForRowAtIndexPath indexPath: NSIndexPath) -> Int {
if indexPath.section == 2 && indexPath.row == 2 {
indexPath = NSIndexPath(forRow: 0, inSection: indexPath.section)
}
return super.tableView(tableView, indentationLevelForRowAtIndexPath: indexPath)
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool{
if text == "\n"
{
descriptionTextView.resignFirstResponder()
return false
}
return true
}
func dateChanged(datePicker: UIDatePicker) {
dueDate = datePicker.date
updateDueDateLabel()
}
}
You have to add just the NSAllowsArbitraryLoads key to YES in NSAppTransportSecurity dictionary in your info.plist file.
For example,
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
I am trying to implement autocompletion, but can't find an example that works in Swift. Below, I'm tring to convert Ray Wenderlich's autocompletion tutorial and example code from 2010. Finally, the code compiles, but the table containing possible completions does not appear, and I don't have the experience to see why it is not unhidden by shouldChangeCharactersInRange.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
let autocompleteTableView = UITableView(frame: CGRectMake(0,80,320,120), style: UITableViewStyle.Plain)
var pastUrls = ["Men", "Women", "Cats", "Dogs", "Children"]
var autocompleteUrls = [String]()
override func viewDidLoad() {
super.viewDidLoad()
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = true
}
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool
{
autocompleteTableView.hidden = false
var substring = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
searchAutocompleteEntriesWithSubstring(substring)
return true // not sure about this - could be false
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
var indexOfPastUrls = 0
for curString in pastUrls
{
let substringRange = curString.rangeOfString(curString)
if (indexOfPastUrls == 0)
{
autocompleteUrls.append(curString)
}
indexOfPastUrls = indexOfPastUrls + 1
}
autocompleteTableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier, forIndexPath: indexPath) as UITableViewCell
let index = indexPath.row as Int
cell.textLabel.text = autocompleteUrls[index]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
textField.text = selectedCell.textLabel.text
}
}
Replace your searchAutocompleteEntriesWithSubstring function content with the one below. I hope it would help you.
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
var myString:NSString! = curString as NSString
var substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
}
The table was not appearing because the UITextField delegate was not to self in viewDidLoad. There was another final issue with the table not showing the autocompletion results, but this is also fixed. Ray Wenderlich's basic Objective-C autocompletion tutorial converted to Swift:
class ViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var textField: UITextField!
#IBOutlet var autocompleteTableView: UITableView!
// #IBOutlet weak var autocompleteTableView = UITableView(frame: CGRectMake(0,80,320,120), style: UITableViewStyle.Plain)
var pastUrls = ["Men", "Women", "Cats", "Dogs", "Children"]
var autocompleteUrls = [String]()
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
autocompleteTableView!.delegate = self
autocompleteTableView!.dataSource = self
autocompleteTableView!.scrollEnabled = true
autocompleteTableView!.hidden = true
}
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool
{
println("banana")
autocompleteTableView!.hidden = false
var substring = (self.textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
searchAutocompleteEntriesWithSubstring(substring)
return true
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
println(substring)
for curString in pastUrls
{
println(curString)
var myString: NSString! = curString as NSString
var substringRange: NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView!.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
var cell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier) as? UITableViewCell
if let tempo1 = cell
{
let index = indexPath.row as Int
cell!.textLabel.text = autocompleteUrls[index]
} else
{
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: autoCompleteRowIdentifier)
}
return cell!
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
textField.text = selectedCell.textLabel.text
}
}
I put together a tutorial that is full of pictures on how to recreate this now 6 year old tutorial
matthewhsingleton.com/coding-with-a-rubber-ducky/2016/5/26/… – RubberDucky4444
For future guys, that might get to work on autocomplete texfield with Swift 2, the code provided by #dane works well. but you have to change this line:
let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier, forIndexPath: indexPath) as UITableViewCell
by
let cell = UITableViewCell(style: UITableViewCellStyle.Default , reuseIdentifier: cellIdentifier)
Also, you might notice that the it is case sensitive, and doesn't work if you enter lowercase string (e.g cats) by default. So to solve this issue you can replace add the option "CaseSensitiveSearch" to the substringRange declaration (in the func searchAutocompleteEntriesWithSubstring). it should look like:
let substringRange :NSRange! = myString.rangeOfString(substring,options [.CaseInsensitiveSearch])
Hope it will help you save one day!!!
Fixed for iOS 9.0 and Swift 2:
import UIKit
class UIAutoCompleteTextField: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak
var textField: UITextField!
let autocompleteTableView = UITableView(frame: CGRectMake(0, 80, 320, 120), style: UITableViewStyle.Plain)
var pastUrls = ["Men", "Women", "Cats", "Dogs", "Children"]
var autocompleteUrls = [String]()
override func viewDidLoad() {
super.viewDidLoad()
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = true
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) - > Bool {
autocompleteTableView.hidden = false
let substring = (textField.text!as NSString).stringByReplacingCharactersInRange(range, withString: string)
searchAutocompleteEntriesWithSubstring(substring)
return true // not sure about this - could be false
}
func searchAutocompleteEntriesWithSubstring(substring: String) {
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls {
let myString: NSString! = curString as NSString
let substringRange: NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0) {
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) - > Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - > UITableViewCell {
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier, forIndexPath: indexPath) as UITableViewCell
let index = indexPath.row as Int
cell.textLabel!.text = autocompleteUrls[index]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath) !
textField.text = selectedCell.textLabel!.text
}
}
Here's a way to add multiple tags based on "#" being typed in like twitter.
Variable typedSubstring is the global substring.
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
autocompleteTableView!.hidden = false
var changedText = (self.textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
var items = changedText.componentsSeparatedByString("#")
if (items.count > 0) {
typedSubstring = "#" + items.lastObject as NSString
self.searchAutocompleteEntriesWithSubstring(typedSubstring)
}
return true
}
Improved on DrWhat's solution so that when you select a cell, it appends it correctly after where the user has already typed in.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
let selectedText = selectedCell.textLabel?.text as String!
// Remove what has been typed already
let trimmedString = selectedText.stringByReplacingOccurrencesOfString(typedSubstring, withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
var currentTextField = textField.text
// then append to what has been typed
textField.text = currentTextField + trimmedString
Got it working with the below. The upper/lower case threw it off initially. I'm using it to autocomplete country names...
import UIKit
class billingAddressViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet var countryTextField: UITextField!
#IBOutlet var countryTableView: UITableView!
var autocompleteCountries = [String]()
// Get list of countries
let countries = NSLocale.ISOCountryCodes().map { (code:String) -> String in
let id = NSLocale.localeIdentifierFromComponents([NSLocaleCountryCode: code])
return NSLocale(localeIdentifier: "en_US").displayNameForKey(NSLocaleIdentifier, value: id) ?? "Country not found for code: \(code)"
}
override func viewDidLoad() {
super.viewDidLoad()
countryTextField.delegate = self
countryTableView!.delegate = self
countryTableView!.dataSource = self
countryTableView!.scrollEnabled = true
countryTableView!.hidden = true
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
print("text field has changed")
countryTableView!.hidden = false
let substring = (self.countryTextField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
print(substring)
searchAutocompleteEntriesWithSubstring(substring)
return true
}
func searchAutocompleteEntriesWithSubstring(substring: String) {
autocompleteCountries.removeAll(keepCapacity: false)
print(substring)
for curString in countries {
//print(curString)
let myString: NSString! = curString.lowercaseString as NSString
let substringRange: NSRange! = myString.rangeOfString(substring.lowercaseString)
if (substringRange.location == 0) {
autocompleteCountries.append(curString)
}
}
countryTableView!.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteCountries.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
var cell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier) as UITableViewCell!
if let tempo1 = cell {
let index = indexPath.row as Int
cell!.textLabel!.text = autocompleteCountries[index]
}
else {
cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: autoCompleteRowIdentifier)
}
return cell!
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
countryTextField.text = selectedCell.textLabel!.text
countryTableView.hidden = true
}
}
table view added without storyboard
class ViewController: UIViewController , UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
var autocompleteTableView: UITableView!
var pastUrls = ["Men", "Women", "Cats", "Dogs", "Children","aaaaaaaaa","aaaaaaaaaaaaaaaaaaa","aaaaaaaaa","a","aa","aaa"]
var autocompleteUrls = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
autocompleteTableView = UITableView(frame: CGRectMake(self.textField.bounds.minX,self.textField.bounds.maxY,self.textField.bounds.width,self.textField.bounds.height * 4), style: UITableViewStyle.Plain)
textField.delegate = self
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = false
autocompleteTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(autocompleteTableView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool
{
autocompleteTableView.hidden = false
var substring = (self.textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
searchAutocompleteEntriesWithSubstring(substring)
return true // not sure about this - could be false
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
var myString:NSString! = curString as NSString
var substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
//autocompleteTableView.hidden = false
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let autoCompleteRowIdentifier = "cell"
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier, forIndexPath: indexPath) as UITableViewCell
let index = indexPath.row as Int
cell.textLabel!.text = autocompleteUrls[index]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
textField.text = self.autocompleteUrls[indexPath.row]
self.autocompleteTableView.hidden = true
}
}
This post helped me thanks, just in case you guys are working with google places API in swift 3 and you need case-insensitive here is the updated code you just have to put:
let subStringRange : NSRange! = myString.range(of: substring, options: .caseInsensitive)
Replace cellForRowAtIndexPath with following function
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
var data = autocompleteUrls[indexPath.row]
cell.textLabel?.text = data as String
return cell
}
Here you have a nice-to-have library in order to simplify that work: https://github.com/apasccon/SearchTextField
Add view.addSubview(autocompleteTableView)
in your viewdidload. It will work.