简体   繁体   English

如何在 Swift 中创建自动完成文本字段

[英]How to create autocomplete text field in Swift

What I want to be able to create is an auto complete text field in iOS.我希望能够创建的是 iOS 中的自动完成文本字段。

I have a form for selecting a client, wherein the user must select a client once using a text field .我有一个用于选择客户端的表单,其中用户必须使用文本字段选择一次客户端。 What I want to happen is when the user writes the first three letters on the text field, I want some service to run a remote web service query using the entered text and present the query results as auto complete suggestions.我想要发生的是当用户在文本字段上写入前三个字母时,我希望某些服务使用输入的文本运行远程 Web 服务查询,并将查询结果显示为自动完成建议。

Below is my current code for my app (iPad only).以下是我的应用程序(仅限 iPad)的当前代码。

   import UIKit

    class AddClientViewController: UIViewController, UITextFieldDelegate {

        @IBOutlet weak var clientTextField:  UITextField!

        var foundList = [String]()


    override func viewDidLoad() {
        super.viewDidLoad()



         let listUrlString =  "http://bla.com/myTextField.php?field=\(clientTextField)"
        let myUrl = NSURL(string: listUrlString);
        let request = NSMutableURLRequest(URL:myUrl!);
        request.HTTPMethod = "GET";

        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in

            if error != nil {
                print(error!.localizedDescription)
                dispatch_sync(dispatch_get_main_queue(),{
                    AWLoader.hide()

                })

                return
            }


            do {

                let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSArray

                if let parseJSON = json {


                    self.foundList = parseJSON as! [String]

                }


        } catch {

            print(error)

        }
    }

    task.resume()
}

Here is the json output that my web service provides.这是我的 Web 服务提供的 json 输出。

["123,John", "343,Smith", "345,April"]

Separated by commas, the first parameter is the client ID and the second parameter is the name of the client.用逗号隔开,第一个参数是client ID ,第二个参数是客户端名称。 John is the name so it should be presented in the auto complete suggestions, which if selected will set the text of the clientTextField to John . John是名字,所以它应该出现在自动完成建议中,如果选择它会将clientTextField的文本设置为John

The current text content of the clientTextField is passed as a GET parameter to my webservice. clientTextField的当前文本内容作为 GET 参数传递给我的网络服务。

I don't know how to do this.我不知道该怎么做。 The user could be typing and not yet finished, while multiple queries could already have been sent.用户可能正在输入但尚未完成,而多个查询可能已经发送。

I did something like this in my app for looking up contacts.我在我的应用程序中做了类似的事情来查找联系人。 I will pseudo code this out for you to understand the concept:我将伪代码出来让你理解这个概念:

1) Capture the characters entered into the textfield by the enduser 1) 捕获最终用户输入到文本字段中的字符

2) At some character count entered decide to query the server to return all entries that match - choose the character count you are comfortable with (I chose around 3-4 characters). 2)在输入的某些字符数决定查询服务器以返回匹配的所有条目 - 选择您喜欢的字符数(我选择了大约 3-4 个字符)。 Fewer returns more, more returns less obviously...up to you, perf and UX considerations.更少的回报更多,更多的回报不那么明显……取决于你,性能和用户体验的考虑。

3) Put the results of this server query into an array on the client. 3) 将此服务器查询的结果放入客户端的数组中。 This will be your superset from which you will offer the suggestions to the user.这将是您的超集,您将从中向用户提供建议。

4) After each subsequent character entered into the text field you will now filter the array (array.filter()) by character string entered to this point. 4) 在文本字段中输入每个后续字符后,您现在将通过输入到该点的字符串过滤数组 (array.filter())。 5) tableView.reloadData() against the filtered array at each character entered. 5) tableView.reloadData() 针对输入的每个字符的过滤数组。

6) I use a dataFlag variable to determine what datasource to show in the tableview depending on what the user is doing. 6)我使用 dataFlag 变量来确定要在 tableview 中显示的数据源,具体取决于用户在做什么。

Note: You only query the server once to minimize perf impact注意:您只查询服务器一次以最小化性能影响

// this function is called automatically when the search control get user focus
func updateSearchResults(for searchController: UISearchController) {
  let searchBar = searchController.searchBar
  if searchBar.text?.range(of: "@") != nil {
    self.getUserByEmail(searchBar.text!)
  }
  if searchController.searchBar.text?.characters.count == 0 && dataFlag != "showParticipants" {
    dataFlag = "showInitSearchData"
    self.contacts.removeAll()
    self.participantTableView.reloadData()
  }
  if dataFlag == "showInitSearchData" && searchController.searchBar.text?.characters.count == 2 {
    self.loadInitialDataSet() {
      self.dataFlag = "showFilteredSearchData"
    }
  }
  if dataFlag == "showFilteredSearchData" {
    self.filterDataForSearchString()
  }

}

// filter results by textfield string
func filterDataForSearchString() {
  let searchString = searchController.searchBar.text
  self.filteredContacts =  self.contacts.filter({
    (contact) -> Bool in
    let contactText: NSString = "\(contact.givenName) \(contact.familyName)" as NSString

  return (contactText.range(of: searchString!, options: NSString.CompareOptions.caseInsensitive).location) != NSNotFound
  })

  DispatchQueue.main.async {
    self.participantTableView.reloadData()
  }  
}

Using Trie like structure will be a better option here.在这里使用类似 Trie 的结构将是更好的选择。 Based on entered string, trie will return top keywords (lets say 10) starting with the entered string.根据输入的字符串,trie 将返回以输入的字符串开头的顶级关键字(比如 10 个)。 Implementing this trie on server side is better.在服务器端实现这个尝试会更好。 When UI makes http call, calculations will be done on server side and server will send top results to UI.当 UI 进行 http 调用时,计算将在服务器端完成,服务器将把最重要的结果发送到 UI。 Then, UI will update TableView with new data.然后,UI 将使用新数据更新 TableView。

You can also do this with hashmap/dictionary but performance will be worse.您也可以使用 hashmap/dictionary 执行此操作,但性能会更差。 Using trie/prefix tree approach will give you the best performance when you have thousands or millions of strings to check.当您要检查数千或数百万个字符串时,使用特里/前缀树方法将为您提供最佳性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM