SwiftUI - Mapkit - 绑定 mapkit 并在注释标注按钮上显示视图
我有一个SwiftUI应用程序,其中显示了一个地图(使用UIViewRepresentable制作的Mapkit)并显示了不同的注释.在每个注释上,我都实现了一个标注按钮,并且我想在按下按钮时完全更改主视图.
I have a SwiftUI app where I show a map (using Mapkit made with UIViewRepresentable) with different annotations being displayed. On each annotation, I have implemented a callout button and I would like to completely change the main View when the button is pressed.
我的想法是使用主视图和地图视图的状态/绑定参数.这个想法可行,但是在使用地图视图"的方式来实现状态/绑定时,我遇到了一些困难.困难在于我将地图用作第二个视图的参数,该视图包含与地图进行交互的菜单.我试图更改我使用地图视图的方式,但没有找到任何解决方案...
My idea was to use a State/Binding parameter of the main view and the mapView. The idea works but I have some difficulties to implement the State/Binding with the way I use the Map View. The difficulty is that I am using the map as a parameter for a second view containing the menu to interact with the map. I tried to change how I use the map view but I did not find any solution...
我的想法是在主体之前创建地图: @State var map = MapView(displaySP:$ displayStorePage)
,但我做不到(错误:无法在其中使用实例成员'$ displayStorePage'属性初始值设定项;属性初始值设定项在'self'可用之前运行)
My idea was to create the map : @State var map = MapView(displaySP: $displayStorePage)
before body but I can not do it (err : Cannot use instance member '$displayStorePage' within property initializer; property initializers run before 'self' is available)
非常欢迎任何帮助:)
显示其他代码,我试图做最轻的版本.
edit: Additional code display, I tried to do the lightest version.
因此在代码中,目标是从激活的用于注释单击的Mapview函数中切换Mainview中的 displayStorePage
.:UIControl)
So in the code, the goal is to toggle the displayStorePage
in Mainview from the Mapview function activated for annotation click func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl)
主视图:
import SwiftUI
import MapKit
struct MainView: View {
@State var researchStore: String = ""
@State var displayStorePage: Bool = false
@State var map = MapView()
var body: some View {
ZStack{
if displayStorePage == false {
VStack{
map.frame(height: 400)
}
TopMapMenu(map: $map)
}
if displayStorePage == true {
Text("This is a win !")
}
}
}
}
MapKit视图:
import Combine
var storeLocation = [MKAnnotation]()
var newAnnotation = MKPointAnnotation()
let mapView = MKMapView()
var displayRedMarker: Bool = true
var displayStore: Bool = false
struct MapView: UIViewRepresentable {
class Coordinator: NSObject, MKMapViewDelegate{
var parent : MapView
init(_ parent: MapView){
self.parent = parent
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "AnnotationView")
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "AnnotationView")
let annotationLabel = UILabel(frame: CGRect(x: -25, y: 12, width: 105, height: 30))
if displayRedMarker {
annotationLabel.text = annotation.title!!
} else {
annotationLabel.text = "Annotation to be hidden"
}
//Other markers done there ....
annotationView?.canShowCallout = true
let btn = UIButton(type: .detailDisclosure)
annotationView?.rightCalloutAccessoryView = btn
return annotationView
}
// Gestion click Annotation button
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
// Here : Changing the Main View parameter : displayStorePage to true
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> some UIView {
let region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 47.510053, longitude: 6.798374),
span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
mapView.delegate = context.coordinator
mapView.showsUserLocation = true
mapView.setRegion(region, animated: false)
mapView.addAnnotation(AddAnnotations())
return mapView
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
func AddAnnotations() -> MKAnnotation {
newAnnotation = MKPointAnnotation()
newAnnotation.title = "Title1"
newAnnotation.coordinate = CLLocationCoordinate2D(latitude: 47.510053, longitude: 6.798374)
return newAnnotation
}
}
TopMenuMap:
struct TopMapMenu: View {
@Binding var map : MapView
@State var searching: Bool = false
@State var redStore: Bool = true
@State var storeFound : Bool = false
var body: some View {
HStack{
VStack(alignment: .leading, spacing: 10){
Button(action: {
displayRedMarker.toggle()
// map.DeleteMarkers()
// map.AddMarkers()
redStore = displayRedMarker
}) {
HStack {
if redStore { Image(systemName: "heart.fill") }
else { Image(systemName: "heart") }
Text("Restaurant")
}
Spacer()
.background(Color(.white))
}
// Other Buttons(Pins) are display here
}// End VStack Pin stores
}
}
}
import SwiftUI
import MapKit
class Store: Identifiable, ObservableObject {
let id: UUID = UUID()
@Published var title: String?
@Published var latitude: Double
@Published var longitude: Double
@Published var displayStoreImage: Bool
@Published var displayRedMarker: Bool
@Published var redStore: Bool
init(title: String, latitude: Double , longitude: Double, displayStoreImage: Bool, displayRedMarker: Bool, redStore: Bool ) {
self.title = title
self.latitude = latitude
self.longitude = longitude
self.displayRedMarker = displayRedMarker
self.displayStoreImage = displayStoreImage
self.redStore = redStore
}
}
extension Store{
var coordinate: CLLocationCoordinate2D{
get{
return CLLocationCoordinate2D(latitude: self.latitude, longitude: self.longitude)
}
}
}
struct MapViewParent: View {
@State var selectedListing: Store?
@State var results: [Store] = [Store(title: "Point 1 title", latitude: 38.3 , longitude: 123.2, displayStoreImage: true, displayRedMarker: true, redStore: false ), Store(title: "Point 2 title", latitude: 38.4 , longitude: 123.1, displayStoreImage: true, displayRedMarker: false, redStore: true )
]
var body: some View {
VStack{
Button("clear-storepage", action: {
selectedListing = nil
})
if selectedListing != nil{
TopMapMenu(results: $results, selectedListing: $selectedListing)
}else{
MapViewAnnotations(selectedListing: $selectedListing, results: $results)
}
}
}
}
struct MapViewAnnotations: View {
@State var region: MKCoordinateRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 38.3 , longitude: 123.2 ), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
@Binding var selectedListing: Store?
@Binding var results: [Store]
var body: some View {
Map(coordinateRegion: $region, annotationItems: results, annotationContent: {
listing in
MapAnnotation(coordinate: listing.coordinate, content: {
Button(action: {
self.selectedListing = listing as Store?
self.region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: listing.coordinate.latitude , longitude: listing.coordinate.longitude ), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
}, label: {
if listing.displayStoreImage{
if listing.displayRedMarker{
Image(systemName: "mappin.circle.fill").foregroundColor(.red).contentShape(Circle())
}else{
Image(systemName: "mappin").foregroundColor(.green).contentShape(Circle())
}
}
else{
Image(systemName: "mappin.circle.fill").foregroundColor(.red).contentShape(Circle())
}
}).buttonStyle(PlainButtonStyle())
})
})
}
}
struct TopMapMenu: View {
@Binding var results: [Store]
@Binding var selectedListing: Store?
var body: some View {
List{
ForEach(results, id: \.id){store in
StoreView(store: store, selectedListing: $selectedListing, results: $results)
}
}
}
}
struct StoreView: View {
@ObservedObject var store: Store
@Binding var selectedListing: Store?
@Binding var results: [Store]
var body: some View{
HStack{
VStack(alignment: .leading, spacing: 10){
Button(action: {
store.displayRedMarker.toggle()
store.redStore = store.displayRedMarker
}, label: {
HStack {
if store.redStore {
Image(systemName: "heart.fill")
}
else { Image(systemName: "heart") }
Text("Restaurant")
}
Spacer()
.background(Color(.white))
}
)}
MapViewAnnotations(selectedListing: $selectedListing, results: Binding(get: {
return [store]
}, set: {
let idx = results.firstIndex(where: {
store.id == $0.id
})
if idx != nil && $0.first != nil{
results[idx!] = $0.first!
}
}))
}
}
}
struct MapViewParent_Previews: PreviewProvider {
static var previews: some View {
MapViewParent()
}
}