swift - SwiftUI - Mapkit - 绑定 mapkit 并在注释标注按钮上显示视图
问题描述
我有一个 SwiftUI 应用程序,我在其中显示了一个地图(使用由 UIViewRepresentable 制作的 Mapkit),其中显示了不同的注释。在每个注释上,我都实现了一个标注按钮,我想在按下按钮时完全更改主视图。
我的想法是使用主视图和地图视图的状态/绑定参数。这个想法有效,但我在使用地图视图的方式实现状态/绑定时遇到了一些困难。困难在于我将地图用作包含与地图交互的菜单的第二个视图的参数。我试图改变我使用地图视图的方式,但我没有找到任何解决方案......
我的想法是创建地图:@State var map = MapView(displaySP: $displayStorePage)
在正文之前但我不能这样做(错误:不能在属性初始化程序中使用实例成员'$displayStorePage';属性初始化程序在'self'可用之前运行)
非常欢迎任何帮助:)
编辑:附加代码显示,我尝试做最轻的版本。
所以在代码中,目标是displayStorePage
从为注释单击激活的 Mapview 功能中切换 Mainviewfunc 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
}
}
顶部菜单地图:
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()
}
}
推荐阅读
- reactive-programming - Spring data couchbase,无法使用反应式编程按id删除文档
- r - 发布闪亮的应用程序时出错:app.R 没有返回闪亮的 appobj 对象
- javascript - 数组长度返回未定义?
- android - Android Webview 不显示 Tron 资源管理器 URL
- r - sparklyr - 在 Apache Spark Join 中包含空值
- php - 使用 PHPSpreadsheet 创建 XLS 文件,不在 Wordpress 范围内工作
- directory - 试图删除注册为变量的目录
- php - Laravel 5.7 Eloquent Relation 上市
- android - MediatorLiveData 源在测试期间不更新
- node.js - 可以“要求();” 返回全局函数/变量?