ios 如何在 Swift 中创建自动完成文本字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35629285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create autocomplete text field in Swift
提问by SwiftDeveloper
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. 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
.
以逗号分隔,第一个参数是client ID
,第二个参数是客户端的名称。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.
我不知道该怎么做。用户可能正在输入但尚未完成,而多个查询可能已经发送。
采纳答案by mafarja
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
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). 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. 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.
5) tableView.reloadData() against the filtered array at each character entered.
6) I use a dataFlag variable to determine what datasource to show in the tableview depending on what the user is doing.
1) 捕获最终用户输入到文本字段中的字符
2) 在输入的某些字符数决定查询服务器以返回所有匹配的条目 - 选择您喜欢的字符数(我选择了大约 3-4 个字符)。更少的回报更多,更多的回报不那么明显……取决于你,性能和用户体验的考虑。
3) 将此服务器查询的结果放入客户端的数组中。这将是您的超集,您将从中向用户提供建议。
4) 在文本字段中输入每个后续字符后,您现在将通过输入到该点的字符串过滤数组 (array.filter())。5) tableView.reloadData() 针对输入的每个字符的过滤数组。
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()
}
}
回答by yalcin
Using Trie like structure will be a better option here. Based on entered string, trie will return top keywords (lets say 10) starting with the entered string. 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. Then, UI will update TableView with new data.
在这里使用类似 Trie 的结构将是更好的选择。根据输入的字符串,trie 将返回以输入的字符串开头的顶级关键字(比如 10 个)。在服务器端实现这个尝试会更好。当 UI 进行 http 调用时,计算将在服务器端完成,服务器将把最重要的结果发送到 UI。然后,UI 将使用新数据更新 TableView。
You can also do this with hashmap/dictionary but performance will be worse. Using trie/prefix tree approach will give you the best performance when you have thousands or millions of strings to check.
您也可以使用 hashmap/dictionary 执行此操作,但性能会更差。当您要检查数千或数百万个字符串时,使用特里/前缀树方法将为您提供最佳性能。