如何结合MAPKIT的UiviewSrestable和实例方法?
对于一个应用程序,我需要显示MAPKIT的地图。 我正在使用Swiftui。 在地图本身的顶部需要有一个搜索功能,当您完成搜索(输入)时,地图将可见区域移至搜索结果,
import MapKit
import SwiftUI
struct MapViewTwo: View {
@Environment(\.presentationMode) var presentationMode
let location: CLLocationCoordinate2D
let annotationItems: [MyAnnotationItem]
@State var searchText = ""
@State private var region: MKCoordinateRegion = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: MapDefaults.latitude, longitude: MapDefaults.longitude),
span: MKCoordinateSpan(latitudeDelta: MapDefaults.zoomedOut, longitudeDelta: MapDefaults.zoomedOut))
private enum MapDefaults {
static let latitude = 51.507222
static let longitude = -0.1275
static let zoomedOut = 2.0
static let zoomedIn = 0.01
}
func searchMap(){
let searchRequest = MKLocalSearch.Request()
searchRequest.naturalLanguageQuery = searchText // This is where you can pass in you search string parameter.
searchRequest.resultTypes = .address
let search = MKLocalSearch(request: searchRequest)
search.start { response, error in
guard let response = response else {
print("Error: \(error?.localizedDescription ?? "Unknown error").")
return
}
print("Found \(response.mapItems.count)")
region = response.boundingRegion
}
}
var body: some View {
Map(coordinateRegion: $region,
interactionModes: .all,
showsUserLocation: true,
annotationItems: annotationItems) { item in
MapPin(coordinate: item.coordinate)
}
ZStack(alignment:.top){
VStack(alignment:.leading){
HStack {
Circle()
.fill(.white)
.frame(width: 44, height: 44)
.overlay( Image(systemName: "arrow.backward"))
.onTapGesture(){
print("Back button")
}
HStack {
Image(systemName: "magnifyingglass")
TextField("search", text: $searchText, onEditingChanged: { isEditing in
}, onCommit: {
print ("Search for \(searchText)")
searchMap()
})
.foregroundColor(.primary)
.textInputAutocapitalization(.never)
Button(action: {
self.searchText = ""
//BACK TO NORMAL
}) {
Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.foregroundColor(.secondary)
.background(Color(.secondarySystemBackground))
.cornerRadius(10.0)
}
}.padding(.top,50).padding(.leading,20).padding(.trailing,20)
}
//MARK: User location button
ZStack(alignment: .bottom){
VStack(alignment:.trailing){
Spacer()
HStack{
Spacer()
Circle()
.fill(.white)
.frame(width: 50, height: 50)
.overlay( Image( "user-location"))
.onTapGesture(){
region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 50.96847915649414, longitude: 5.982074737548828),
span: MKCoordinateSpan(latitudeDelta: MapDefaults.zoomedOut, longitudeDelta: MapDefaults.zoomedOut))
}
}.padding(.bottom,100).padding(.trailing,30)
}
}
.ignoresSafeArea()
.onAppear(perform: setupLocation)
}
func setupLocation() {
region = MKCoordinateRegion(
center: location,
span: MKCoordinateSpan(latitudeDelta: MapDefaults.zoomedIn, longitudeDelta: MapDefaults.zoomedIn))
}
}
我还需要具有用户可以在地图(中心)并选择销钉,然后将其移至其他位置。当他这样做时,Glgeocoder将逆转地理位置位置,并就某些文本元素提供此反馈。
为此,我有以下代码(游乐场)。
- tryview(我的视图显示DropapinMapView和搜索栏
- DropaPinMapView处理拖放和地理编码
#TryView.swift
import SwiftUI
import MapKit
struct TryView: View {
@State var mapItems: [MKMapItem] = []
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@State var isPinDropped:Bool = false
@State var showSearchResults:Bool = false
@State var searchText = ""
@State private var showCancelButton: Bool = false
@State var pinDropDetail = PinDropDetail(address: "", locality: "", postalCode: "", latitude: 50.96847915649414, longitude: 5.98207473754882, coordinateString: "",isBack: false)
@Binding var model: PinDropDetail
var onDismiss: ((_ model: PinDropDetail) -> Void)?
func searchMap(){
let searchRequest = MKLocalSearch.Request()
searchRequest.naturalLanguageQuery = searchText // This is where you can pass in you search string parameter.
searchRequest.resultTypes = .address
let search = MKLocalSearch(request: searchRequest)
search.start { response, error in
guard let response = response else {
print("Error: \(error?.localizedDescription ?? "Unknown error").")
return
}
//NOW I WANT TO MAP TO ANIMATE AND SET THE REGION TO response.boundingRegion
}
}
var body: some View {
DropAPinMapView(pinDropDetail:self.$pinDropDetail )
.ignoresSafeArea()
//MARK: controls
//search bar
ZStack(alignment:.top){
VStack(alignment:.leading){
HStack {
Circle()
.fill(.white)
.frame(width: 44, height: 44)
.overlay( Image(systemName: "arrow.backward"))
.onTapGesture(){
print("Back button")
}
HStack {
Image(systemName: "magnifyingglass")
TextField("search", text: $searchText, onEditingChanged: { isEditing in
}, onCommit: {
print ("Search for \(searchText)")
searchMap()
})
.foregroundColor(.primary)
.textInputAutocapitalization(.never)
Button(action: {
self.searchText = ""
}) {
Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.foregroundColor(.secondary)
.background(Color(.secondarySystemBackground))
.cornerRadius(10.0)
}
}.padding(.top,50).padding(.leading,20).padding(.trailing,20)
}
.ignoresSafeArea()
//MARK: User location button
ZStack(alignment: .bottom){
VStack(alignment:.trailing){
Spacer()
HStack{
Spacer()
Circle()
.fill(.white)
.frame(width: 50, height: 50)
.overlay( Image( "user-location"))
.onTapGesture(){
print("Userlocation")
}
}.padding(.bottom,100).padding(.trailing,30)
}
}
.ignoresSafeArea()
//MARK: end of controls
//IN APP THIS IS A DIFFERENT CONTROL DISPLAYING THE RESULT OF THE PINDROP
Text(pinDropDetail.address).foregroundColor(.red)
}
}
dropapinmapview
import SwiftUI
import MapKit
import Foundation
struct PinDropDetail {
var address: String
var locality: String
var postalCode: String
var latutide: Double
var longitude:Double
var coordinateString: String
var isBack: Bool
init(address:String,locality:String,postalCode:String,latitude:Double,longitude:Double,coordinateString:String,isBack:Bool){
self.address = address
self.locality = locality
self.postalCode = postalCode
self.latutide = latitude
self.longitude = longitude
self.coordinateString = coordinateString
self.isBack = isBack
}
}
struct DropAPinMapView: UIViewRepresentable {
let coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude:50.96847915649414,longitude: 5.98207473754882)
@Binding var pinDropDetail: PinDropDetail
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.mapType = .standard//.hybrid
map.delegate = context.coordinator
let coordinate: CLLocationCoordinate2D = coordinate
let region = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 0.3, longitudeDelta: 0.3))
map.setRegion(map.regionThatFits(region), animated: true)
map.showsCompass = true
map.showsUserLocation = true
let annotation = MKPointAnnotation()
annotation.coordinate = self.coordinate
map.addAnnotation(annotation)
//geocode initial state as well
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)) { places, error in
let latitudeString = String(format: "%.5f",coordinate.latitude)
let longitudeString = String(format: "%.5f", coordinate.longitude)
self.pinDropDetail.coordinateString = latitudeString + " , " + longitudeString
self.pinDropDetail.address = (places?.first?.name!)! + ", " + (places?.first?.locality!)!
self.pinDropDetail.postalCode = (places?.first?.postalCode!)!
self.pinDropDetail.locality = (places?.first?.locality!)!
self.pinDropDetail.latutide = coordinate.latitude
self.pinDropDetail.longitude = coordinate.longitude
}
return map
}
func updateUIView(_ uiView: MKMapView, context: Context) {
}
func makeCoordinator() -> DropAPinMapView.Coordinator {
return DropAPinMapView.Coordinator(parent1: self)
}
final class Coordinator: NSObject, MKMapViewDelegate {
var parent:DropAPinMapView
init(parent1:DropAPinMapView){
parent = parent1
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
pin.isDraggable = true
pin.pinTintColor = .red
pin.animatesDrop = true
return pin
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationView.DragState, fromOldState oldState: MKAnnotationView.DragState) {
//print(view.annotation?.coordinate.latitude)
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: (view.annotation?.coordinate.latitude)!, longitude: (view.annotation?.coordinate.longitude)!)) { places, error in
let lat = (view.annotation?.coordinate.latitude)!
let lon = (view.annotation?.coordinate.longitude)!
let latitudeString = String(format: "%.5f",lat)
let longitudeString = String(format: "%.5f", lon)
self.parent.pinDropDetail.coordinateString = latitudeString + " , " + longitudeString
self.parent.pinDropDetail.address = (places?.first?.name!)! + ", " + (places?.first?.locality!)!
self.parent.pinDropDetail.postalCode = places?.first?.postalCode ?? ""
self.parent.pinDropDetail.locality = places?.first?.locality ?? ""
self.parent.pinDropDetail.latutide = (view.annotation?.coordinate.latitude)!
self.parent.pinDropDetail.longitude = (view.annotation?.coordinate.longitude)!
}
}
}
}
您看到了第一个方法(搜索)(搜索)简单地使用映射,而第二个问题也可以使用。第二个问题也可以使用。为了创建UiviewSrestentable,
我如何将两个功能结合在一个解决方案中? 如果可以实例化DropaPinMapView,那么可以调用函数。我尝试添加一个也有效的静态函数,但是该行使
let map = MKMapView()
地图对象私有
请提供解决方案,提示或想法
For an app I need to display a Map from mapkit.
I'm using SwiftUI.
On top of the Map itself there need to be a search function and when you finish the search (enter) the map moves the visible region to the result of the search
import MapKit
import SwiftUI
struct MapViewTwo: View {
@Environment(\.presentationMode) var presentationMode
let location: CLLocationCoordinate2D
let annotationItems: [MyAnnotationItem]
@State var searchText = ""
@State private var region: MKCoordinateRegion = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: MapDefaults.latitude, longitude: MapDefaults.longitude),
span: MKCoordinateSpan(latitudeDelta: MapDefaults.zoomedOut, longitudeDelta: MapDefaults.zoomedOut))
private enum MapDefaults {
static let latitude = 51.507222
static let longitude = -0.1275
static let zoomedOut = 2.0
static let zoomedIn = 0.01
}
func searchMap(){
let searchRequest = MKLocalSearch.Request()
searchRequest.naturalLanguageQuery = searchText // This is where you can pass in you search string parameter.
searchRequest.resultTypes = .address
let search = MKLocalSearch(request: searchRequest)
search.start { response, error in
guard let response = response else {
print("Error: \(error?.localizedDescription ?? "Unknown error").")
return
}
print("Found \(response.mapItems.count)")
region = response.boundingRegion
}
}
var body: some View {
Map(coordinateRegion: $region,
interactionModes: .all,
showsUserLocation: true,
annotationItems: annotationItems) { item in
MapPin(coordinate: item.coordinate)
}
ZStack(alignment:.top){
VStack(alignment:.leading){
HStack {
Circle()
.fill(.white)
.frame(width: 44, height: 44)
.overlay( Image(systemName: "arrow.backward"))
.onTapGesture(){
print("Back button")
}
HStack {
Image(systemName: "magnifyingglass")
TextField("search", text: $searchText, onEditingChanged: { isEditing in
}, onCommit: {
print ("Search for \(searchText)")
searchMap()
})
.foregroundColor(.primary)
.textInputAutocapitalization(.never)
Button(action: {
self.searchText = ""
//BACK TO NORMAL
}) {
Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.foregroundColor(.secondary)
.background(Color(.secondarySystemBackground))
.cornerRadius(10.0)
}
}.padding(.top,50).padding(.leading,20).padding(.trailing,20)
}
//MARK: User location button
ZStack(alignment: .bottom){
VStack(alignment:.trailing){
Spacer()
HStack{
Spacer()
Circle()
.fill(.white)
.frame(width: 50, height: 50)
.overlay( Image( "user-location"))
.onTapGesture(){
region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 50.96847915649414, longitude: 5.982074737548828),
span: MKCoordinateSpan(latitudeDelta: MapDefaults.zoomedOut, longitudeDelta: MapDefaults.zoomedOut))
}
}.padding(.bottom,100).padding(.trailing,30)
}
}
.ignoresSafeArea()
.onAppear(perform: setupLocation)
}
func setupLocation() {
region = MKCoordinateRegion(
center: location,
span: MKCoordinateSpan(latitudeDelta: MapDefaults.zoomedIn, longitudeDelta: MapDefaults.zoomedIn))
}
}
I also need to have the functionality that a user can drop a pin on the map (center) and select the pin and move it to a different location. When he does, the GLGeocoder will reverse geocode the location and provide this feedback on some Text elements.
For this I have the following code (playgrounds).
- TryView (my view to display the DropApinMapView and search bar
- DropAPinMapView handling the drag and drop and geocoding
#TryView.swift
import SwiftUI
import MapKit
struct TryView: View {
@State var mapItems: [MKMapItem] = []
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@State var isPinDropped:Bool = false
@State var showSearchResults:Bool = false
@State var searchText = ""
@State private var showCancelButton: Bool = false
@State var pinDropDetail = PinDropDetail(address: "", locality: "", postalCode: "", latitude: 50.96847915649414, longitude: 5.98207473754882, coordinateString: "",isBack: false)
@Binding var model: PinDropDetail
var onDismiss: ((_ model: PinDropDetail) -> Void)?
func searchMap(){
let searchRequest = MKLocalSearch.Request()
searchRequest.naturalLanguageQuery = searchText // This is where you can pass in you search string parameter.
searchRequest.resultTypes = .address
let search = MKLocalSearch(request: searchRequest)
search.start { response, error in
guard let response = response else {
print("Error: \(error?.localizedDescription ?? "Unknown error").")
return
}
//NOW I WANT TO MAP TO ANIMATE AND SET THE REGION TO response.boundingRegion
}
}
var body: some View {
DropAPinMapView(pinDropDetail:self.$pinDropDetail )
.ignoresSafeArea()
//MARK: controls
//search bar
ZStack(alignment:.top){
VStack(alignment:.leading){
HStack {
Circle()
.fill(.white)
.frame(width: 44, height: 44)
.overlay( Image(systemName: "arrow.backward"))
.onTapGesture(){
print("Back button")
}
HStack {
Image(systemName: "magnifyingglass")
TextField("search", text: $searchText, onEditingChanged: { isEditing in
}, onCommit: {
print ("Search for \(searchText)")
searchMap()
})
.foregroundColor(.primary)
.textInputAutocapitalization(.never)
Button(action: {
self.searchText = ""
}) {
Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
.foregroundColor(.secondary)
.background(Color(.secondarySystemBackground))
.cornerRadius(10.0)
}
}.padding(.top,50).padding(.leading,20).padding(.trailing,20)
}
.ignoresSafeArea()
//MARK: User location button
ZStack(alignment: .bottom){
VStack(alignment:.trailing){
Spacer()
HStack{
Spacer()
Circle()
.fill(.white)
.frame(width: 50, height: 50)
.overlay( Image( "user-location"))
.onTapGesture(){
print("Userlocation")
}
}.padding(.bottom,100).padding(.trailing,30)
}
}
.ignoresSafeArea()
//MARK: end of controls
//IN APP THIS IS A DIFFERENT CONTROL DISPLAYING THE RESULT OF THE PINDROP
Text(pinDropDetail.address).foregroundColor(.red)
}
}
DropAPinMapView
import SwiftUI
import MapKit
import Foundation
struct PinDropDetail {
var address: String
var locality: String
var postalCode: String
var latutide: Double
var longitude:Double
var coordinateString: String
var isBack: Bool
init(address:String,locality:String,postalCode:String,latitude:Double,longitude:Double,coordinateString:String,isBack:Bool){
self.address = address
self.locality = locality
self.postalCode = postalCode
self.latutide = latitude
self.longitude = longitude
self.coordinateString = coordinateString
self.isBack = isBack
}
}
struct DropAPinMapView: UIViewRepresentable {
let coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude:50.96847915649414,longitude: 5.98207473754882)
@Binding var pinDropDetail: PinDropDetail
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView()
map.mapType = .standard//.hybrid
map.delegate = context.coordinator
let coordinate: CLLocationCoordinate2D = coordinate
let region = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 0.3, longitudeDelta: 0.3))
map.setRegion(map.regionThatFits(region), animated: true)
map.showsCompass = true
map.showsUserLocation = true
let annotation = MKPointAnnotation()
annotation.coordinate = self.coordinate
map.addAnnotation(annotation)
//geocode initial state as well
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)) { places, error in
let latitudeString = String(format: "%.5f",coordinate.latitude)
let longitudeString = String(format: "%.5f", coordinate.longitude)
self.pinDropDetail.coordinateString = latitudeString + " , " + longitudeString
self.pinDropDetail.address = (places?.first?.name!)! + ", " + (places?.first?.locality!)!
self.pinDropDetail.postalCode = (places?.first?.postalCode!)!
self.pinDropDetail.locality = (places?.first?.locality!)!
self.pinDropDetail.latutide = coordinate.latitude
self.pinDropDetail.longitude = coordinate.longitude
}
return map
}
func updateUIView(_ uiView: MKMapView, context: Context) {
}
func makeCoordinator() -> DropAPinMapView.Coordinator {
return DropAPinMapView.Coordinator(parent1: self)
}
final class Coordinator: NSObject, MKMapViewDelegate {
var parent:DropAPinMapView
init(parent1:DropAPinMapView){
parent = parent1
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
pin.isDraggable = true
pin.pinTintColor = .red
pin.animatesDrop = true
return pin
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationView.DragState, fromOldState oldState: MKAnnotationView.DragState) {
//print(view.annotation?.coordinate.latitude)
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: (view.annotation?.coordinate.latitude)!, longitude: (view.annotation?.coordinate.longitude)!)) { places, error in
let lat = (view.annotation?.coordinate.latitude)!
let lon = (view.annotation?.coordinate.longitude)!
let latitudeString = String(format: "%.5f",lat)
let longitudeString = String(format: "%.5f", lon)
self.parent.pinDropDetail.coordinateString = latitudeString + " , " + longitudeString
self.parent.pinDropDetail.address = (places?.first?.name!)! + ", " + (places?.first?.locality!)!
self.parent.pinDropDetail.postalCode = places?.first?.postalCode ?? ""
self.parent.pinDropDetail.locality = places?.first?.locality ?? ""
self.parent.pinDropDetail.latutide = (view.annotation?.coordinate.latitude)!
self.parent.pinDropDetail.longitude = (view.annotation?.coordinate.longitude)!
}
}
}
}
You see two different approaches for the first one (search) simply using a Map and that works. The second problem drop a pin also works but requires to create the UIViewRepresentable
How can I combine the two functionalities in one solution?
It would be great if the DropAPinMapView could be instantiated so a function could be called. I've tried adding a static function which also works but the line
let map = MKMapView()
Makes the map object private
Please provide solutions, tips or ideas
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
注入
mkmapview()
来自父母的实例。它是一种参考类型,因此父母将是所有者,并且可以在内部代表渲染的内部使用相同的参考时使用它。所以看起来像
Inject
MKMapView()
instance from parent. It is a reference type, so parent will be an owner and will be able to work with it while the same reference is used inside representable for rendering.So it would look like