我有一个表单,用户可以输入他们的地址。尽管他们总是可以手动输入,但我也想提供自动完成的简便解决方案,这样他们只需开始键入他们的地址,然后从列表中点击正确的地址,并使其自动填充各个字段。
我首先从jnpdx的Swift5解决方案开始工作 - https://dev59.com/gVwX5IYBdhLWcg3wyCDT#67131376 然而,有两个问题我无法解决:
我首先从jnpdx的Swift5解决方案开始工作 - https://dev59.com/gVwX5IYBdhLWcg3wyCDT#67131376 然而,有两个问题我无法解决:
我需要结果仅限于美国(不仅仅是大陆美国,而是包括阿拉斯加、夏威夷和波多黎各的整个美国)。我知道MKCoordinateRegion如何使用中心点和缩放范围,但它似乎不能在地址搜索的结果上工作。
结果只提供标题和副标题,我需要实际提取所有个人地址信息并填充我的变量(例如地址、城市、州、邮政编码和邮政编码扩展)。如果用户有公寓或套房号码,他们将自己填写。我的想法是创建一个函数,在按钮被点击时运行,这样基于用户的选择来分配变量,但我不知道如何提取所需的各种信息。苹果的文档像往常一样糟糕,我没有找到任何解释如何做这件事的教程。
这是最新的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
private var currentPromise
这一行上我得到了泛型类型'Result'特化了太多类型参数(得到了2个,但期望1个)
的错误提示。 - soleilMKPlacemark
是CLPlacemark
的子类。所以不需要进行额外的反向地理搜索。因此,您可以直接获取地标(placemark)而不是获取CLCoordinate
,然后立即初始化ReversedGeoLocation
。文档在这里。 - undefined