更新 SwiftUI Mapbox 地图视图以在按下按钮时显示新的引脚注释
Updating a SwiftUI Mapbox Map View to Show New Pin Annotations on a Button Press
我有一个 SwiftUI 项目,我想在其中将地址地理编码转发到坐标并更新 Mapbox 地图视图以在按下按钮时在该地址的坐标处显示图钉注释。
按下我创建的按钮时,该操作似乎有效,但地图不会在任何地方显示新的图钉,即使我的注释数组(用于图钉放置)已更新为新地址的信息。
我的内容和地图视图如下:
MapView
import SwiftUI
import Mapbox
extension MGLPointAnnotation {
convenience init(title: String, coordinate: CLLocationCoordinate2D) {
self.init()
self.title = title
self.coordinate = coordinate
}
}
struct MapView: UIViewRepresentable {
var mapView: MGLMapView = MGLMapView(frame: .zero, styleURL: MGLStyle.streetsStyleURL)
@Binding var annotations: [MGLPointAnnotation]
final class Coordinator: NSObject, MGLMapViewDelegate {
var control: MapView
init(_ control: MapView) {
self.control = control
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
return nil
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
}
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MGLMapView {
mapView.delegate = context.coordinator
return mapView
}
func styleURL(_ styleURL: URL) -> MapView {
mapView.styleURL = styleURL
return self
}
func centerCoordinate(_ centerCoordinate: CLLocationCoordinate2D) -> MapView {
mapView.centerCoordinate = centerCoordinate
return self
}
func zoomLevel(_ zoomLevel: Double) -> MapView {
mapView.zoomLevel = zoomLevel
return self
}
func updateUIView(_ uiView: MGLMapView, context: UIViewRepresentableContext<MapView>) {
updateAnnotations()
}
func makeCoordinator() -> MapView.Coordinator {
Coordinator(self)
}
private func updateAnnotations() {
if let currentAnnotations = mapView.annotations {
mapView.removeAnnotations(currentAnnotations)
}
mapView.addAnnotations(annotations)
}
}
ContentView
import SwiftUI
import Mapbox
import CoreLocation
struct ContentView: View {
@ObservedObject var VModel = ViewModel()
@ObservedObject var locationManager = LocationManager()
var userLatitude: CLLocationDegrees {
return (locationManager.lastLocation?.coordinate.latitude ?? 0)
}
var userLongitude: CLLocationDegrees {
return (locationManager.lastLocation?.coordinate.longitude ?? 0)
}
var lat: Double {
return (VModel.lat ?? 0)
}
var long: Double {
return (VModel.lon ?? 0)
}
@State var searchedLocation: String = ""
@State var annotations = [
MGLPointAnnotation(title: "Mapbox", coordinate: .init(latitude: 37.791434, longitude: -122.396267))
]
var body: some View {
VStack{
ZStack(alignment: Alignment(horizontal: .leading, vertical: .top)){
MapView(annotations: $annotations).centerCoordinate(.init(latitude: self.lat, longitude: self.long)).zoomLevel(16).edgesIgnoringSafeArea(.all)
VStack{
Button(action: {
self.VModel.fetchCoords(address: "address")
let delayInSeconds = 3.0
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
self.annotations.append(MGLPointAnnotation(title: "Home", coordinate: .init(latitude: self.lat, longitude: self.long)))
}
print("\(self.annotations)")
}, label: {Text("Press to update annotation")})
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
非常感谢任何有关更新地图以在按下按钮时显示新图钉注释的信息。如果需要更多信息,请发表评论
在不了解您的 VModel
到 LocationManager
的情况下,我将它们剥离出来,并为某些注释硬编码了一些值。因此,尽管下面的代码是您的简化版,但您可以在按下按钮时看到添加了第三个注释。
这是一个简单的实现,其中控制注释的视图模型 (AnnotationsVM
) 在 ContextView
中被引用为 @ObservedObject
。它发布注释数组。这些被传递到 MapView
中的 @Binding
变量,当该数组发生变化(添加、删除等)时,updateUIView 方法更新地图。
import SwiftUI
import Mapbox
class MapViewCoordinator: NSObject, MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
}
struct MapView: UIViewRepresentable {
@Binding var annos: [MGLPointAnnotation]
func makeUIView(context: Context) -> MGLMapView {
let map = MGLMapView()
map.styleURL = MGLStyle.outdoorsStyleURL
map.delegate = context.coordinator
let location = CLLocation(latitude: 40.763783, longitude: -73.973133)
map.setCenter(location.coordinate, zoomLevel: 13, animated: true)
return map
}
func updateUIView(_ uiView: MGLMapView, context: Context) {
if let currentAnnotations = uiView.annotations {
uiView.removeAnnotations(currentAnnotations)
}
uiView.addAnnotations(annos)
}
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator()
}
}
struct ContentView: View {
@ObservedObject var annotationsVM = AnnotationsVM()
var body: some View {
NavigationView {
MapView(annos: $annotationsVM.annos)
.navigationBarTitle(Text("Hello"))
.navigationBarItems(trailing: Button(action: {
self.annotationsVM.addNextAnnotation()
}, label: {
Image(systemName: "plus.circle")
}))
}
}
}
class AnnotationsVM: ObservableObject {
@Published var annos = [MGLPointAnnotation]()
init() {
var annotation = MGLPointAnnotation()
annotation.title = "Apple Store"
annotation.coordinate = CLLocationCoordinate2D(latitude: 40.77, longitude: -73.98)
annotation.subtitle = "Think Different"
annos.append(annotation)
annotation = MGLPointAnnotation()
annotation.title = "Shoe Store"
annotation.coordinate = CLLocationCoordinate2D(latitude: 40.78, longitude: -73.98)
annotation.subtitle = "Shoe Different"
annos.append(annotation)
}
func addNextAnnotation() {
let newAnnotation = MGLPointAnnotation()
newAnnotation.title = "New Annotation"
newAnnotation.coordinate = CLLocationCoordinate2D(latitude: 40.763783, longitude: -73.973133)
newAnnotation.subtitle = "Ben Button"
annos.append(newAnnotation)
}
}
我有一个 SwiftUI 项目,我想在其中将地址地理编码转发到坐标并更新 Mapbox 地图视图以在按下按钮时在该地址的坐标处显示图钉注释。
按下我创建的按钮时,该操作似乎有效,但地图不会在任何地方显示新的图钉,即使我的注释数组(用于图钉放置)已更新为新地址的信息。
我的内容和地图视图如下:
MapView
import SwiftUI
import Mapbox
extension MGLPointAnnotation {
convenience init(title: String, coordinate: CLLocationCoordinate2D) {
self.init()
self.title = title
self.coordinate = coordinate
}
}
struct MapView: UIViewRepresentable {
var mapView: MGLMapView = MGLMapView(frame: .zero, styleURL: MGLStyle.streetsStyleURL)
@Binding var annotations: [MGLPointAnnotation]
final class Coordinator: NSObject, MGLMapViewDelegate {
var control: MapView
init(_ control: MapView) {
self.control = control
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
return nil
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
}
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MGLMapView {
mapView.delegate = context.coordinator
return mapView
}
func styleURL(_ styleURL: URL) -> MapView {
mapView.styleURL = styleURL
return self
}
func centerCoordinate(_ centerCoordinate: CLLocationCoordinate2D) -> MapView {
mapView.centerCoordinate = centerCoordinate
return self
}
func zoomLevel(_ zoomLevel: Double) -> MapView {
mapView.zoomLevel = zoomLevel
return self
}
func updateUIView(_ uiView: MGLMapView, context: UIViewRepresentableContext<MapView>) {
updateAnnotations()
}
func makeCoordinator() -> MapView.Coordinator {
Coordinator(self)
}
private func updateAnnotations() {
if let currentAnnotations = mapView.annotations {
mapView.removeAnnotations(currentAnnotations)
}
mapView.addAnnotations(annotations)
}
}
ContentView
import SwiftUI
import Mapbox
import CoreLocation
struct ContentView: View {
@ObservedObject var VModel = ViewModel()
@ObservedObject var locationManager = LocationManager()
var userLatitude: CLLocationDegrees {
return (locationManager.lastLocation?.coordinate.latitude ?? 0)
}
var userLongitude: CLLocationDegrees {
return (locationManager.lastLocation?.coordinate.longitude ?? 0)
}
var lat: Double {
return (VModel.lat ?? 0)
}
var long: Double {
return (VModel.lon ?? 0)
}
@State var searchedLocation: String = ""
@State var annotations = [
MGLPointAnnotation(title: "Mapbox", coordinate: .init(latitude: 37.791434, longitude: -122.396267))
]
var body: some View {
VStack{
ZStack(alignment: Alignment(horizontal: .leading, vertical: .top)){
MapView(annotations: $annotations).centerCoordinate(.init(latitude: self.lat, longitude: self.long)).zoomLevel(16).edgesIgnoringSafeArea(.all)
VStack{
Button(action: {
self.VModel.fetchCoords(address: "address")
let delayInSeconds = 3.0
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
self.annotations.append(MGLPointAnnotation(title: "Home", coordinate: .init(latitude: self.lat, longitude: self.long)))
}
print("\(self.annotations)")
}, label: {Text("Press to update annotation")})
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
非常感谢任何有关更新地图以在按下按钮时显示新图钉注释的信息。如果需要更多信息,请发表评论
在不了解您的 VModel
到 LocationManager
的情况下,我将它们剥离出来,并为某些注释硬编码了一些值。因此,尽管下面的代码是您的简化版,但您可以在按下按钮时看到添加了第三个注释。
这是一个简单的实现,其中控制注释的视图模型 (AnnotationsVM
) 在 ContextView
中被引用为 @ObservedObject
。它发布注释数组。这些被传递到 MapView
中的 @Binding
变量,当该数组发生变化(添加、删除等)时,updateUIView 方法更新地图。
import SwiftUI
import Mapbox
class MapViewCoordinator: NSObject, MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
}
struct MapView: UIViewRepresentable {
@Binding var annos: [MGLPointAnnotation]
func makeUIView(context: Context) -> MGLMapView {
let map = MGLMapView()
map.styleURL = MGLStyle.outdoorsStyleURL
map.delegate = context.coordinator
let location = CLLocation(latitude: 40.763783, longitude: -73.973133)
map.setCenter(location.coordinate, zoomLevel: 13, animated: true)
return map
}
func updateUIView(_ uiView: MGLMapView, context: Context) {
if let currentAnnotations = uiView.annotations {
uiView.removeAnnotations(currentAnnotations)
}
uiView.addAnnotations(annos)
}
func makeCoordinator() -> MapViewCoordinator {
return MapViewCoordinator()
}
}
struct ContentView: View {
@ObservedObject var annotationsVM = AnnotationsVM()
var body: some View {
NavigationView {
MapView(annos: $annotationsVM.annos)
.navigationBarTitle(Text("Hello"))
.navigationBarItems(trailing: Button(action: {
self.annotationsVM.addNextAnnotation()
}, label: {
Image(systemName: "plus.circle")
}))
}
}
}
class AnnotationsVM: ObservableObject {
@Published var annos = [MGLPointAnnotation]()
init() {
var annotation = MGLPointAnnotation()
annotation.title = "Apple Store"
annotation.coordinate = CLLocationCoordinate2D(latitude: 40.77, longitude: -73.98)
annotation.subtitle = "Think Different"
annos.append(annotation)
annotation = MGLPointAnnotation()
annotation.title = "Shoe Store"
annotation.coordinate = CLLocationCoordinate2D(latitude: 40.78, longitude: -73.98)
annotation.subtitle = "Shoe Different"
annos.append(annotation)
}
func addNextAnnotation() {
let newAnnotation = MGLPointAnnotation()
newAnnotation.title = "New Annotation"
newAnnotation.coordinate = CLLocationCoordinate2D(latitude: 40.763783, longitude: -73.973133)
newAnnotation.subtitle = "Ben Button"
annos.append(newAnnotation)
}
}