我有一个表格,用户可以在其中输入他们的地址。虽然他们总是可以手动输入,但我也想为他们提供一个简单的自动完成解决方案,这样他们就可以开始输入他们的地址,然后从列表中点击正确的地址并让它自动填充各个字段。
我开始使用 jnpdx 的 Swift5 解决方案 - https://stackoverflow.com/a/67131376/11053343
但是,有两个问题我似乎无法解决:
我需要将结果仅限于美国(不仅仅是美国大陆,而是整个美国,包括阿拉斯加、夏威夷和波多黎各)。我知道 MKCoordinateRegion 如何与中心点一起工作,然后是缩放传播,但它似乎不适用于地址搜索的结果。
结果的返回只提供了标题和副标题,我需要在其中实际提取所有单独的地址信息并填充我的变量(即地址、城市、州、zip 和 zip ext)。如果用户有一个 apt 或套件号码,他们会自己填写。我的想法是创建一个在点击按钮时运行的函数,以便根据用户的选择分配变量,但我不知道如何提取所需的各种信息。苹果的文档和往常一样糟糕,我还没有找到任何解释如何做到这一点的教程。
这是最新的 SwiftUI 和 XCode (ios15+)。
我创建了一个用于测试的虚拟表单。这是我所拥有的:
import SwiftUI
import Combine
import MapKit
class MapSearch : NSObject, ObservableObject {
@Published var locationResults : [MKLocalSearchCompletion] = []
@Published var searchTerm = ""
private var cancellables : Set<AnyCancellable> = []
private var searchCompleter = MKLocalSearchCompleter()
private var currentPromise : ((Result<[MKLocalSearchCompletion], Error>) -> Void)?
override init() {
super.init()
searchCompleter.delegate = self
searchCompleter.region = MKCoordinateRegion()
searchCompleter.resultTypes = MKLocalSearchCompleter.ResultType([.address])
$searchTerm
.debounce(for: .seconds(0.5), scheduler: RunLoop.main)
.removeDuplicates()
.flatMap({ (currentSearchTerm) in
self.searchTermToResults(searchTerm: currentSearchTerm)
})
.sink(receiveCompletion: { (completion) in
//handle error
}, receiveValue: { (results) in
self.locationResults = results
})
.store(in: &cancellables)
}
func searchTermToResults(searchTerm: String) -> Future<[MKLocalSearchCompletion], Error> {
Future { promise in
self.searchCompleter.queryFragment = searchTerm
self.currentPromise = promise
}
}
}
extension MapSearch : MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
currentPromise?(.success(completer.results))
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
//currentPromise?(.failure(error))
}
}
struct MapKit_Interface: View {
@StateObject private var mapSearch = MapSearch()
@State private var address = ""
@State private var addrNum = ""
@State private var city = ""
@State private var state = ""
@State private var zip = ""
@State private var zipExt = ""
var body: some View {
List {
Section {
TextField("Search", text: $mapSearch.searchTerm)
ForEach(mapSearch.locationResults, id: \.self) { location in
Button {
// Function code goes here
} label: {
VStack(alignment: .leading) {
Text(location.title)
.foregroundColor(Color.white)
Text(location.subtitle)
.font(.system(.caption))
.foregroundColor(Color.white)
}
} // End Label
} // End ForEach
} // End Section
Section {
TextField("Address", text: $address)
TextField("Apt/Suite", text: $addrNum)
TextField("City", text: $city)
TextField("State", text: $state)
TextField("Zip", text: $zip)
TextField("Zip-Ext", text: $zipExt)
} // End Section
} // End List
} // End var Body
} // End Struct