SwiftUI MapKit UIViewRepresentable 无法显示警报
SwiftUI MapKit UIViewRepresentable Can't present Alert
我有一个 SwiftUI 应用程序,其中有几个视图是使用 MapKit 制作的地图
UIViewRepresentable。我有兴趣点和使用的自定义注释
用于进一步操作的左右标注按钮。在右边我只是想要
显示有关航路点的信息。在左侧,我想发出警报
进一步操作的选择 - 例如,插入一个新的注释点。前
SwiftUI 我刚刚发出警报并执行了上述两项操作。但据我所知,
UIViewRepresentable 版本上没有 self.present。因此我没有去过
能够显示警报。
只是为了实验 - 我将 SwiftUI 警报代码附加到 SwiftUI 视图
调用地图视图。使用 Observable 布尔值我确实可以引发这两个警报。
这对我来说似乎很奇怪,但也许是绑定到全局属性的警报代码
可以在任何地方。
我的第一次尝试:(结构是 DetailMapView)
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.leftCalloutAccessoryView {
guard let tappedLocationCoord = view.annotation?.coordinate else {return}
let tappedLocation = CLLocation(latitude: tappedLocationCoord.latitude, longitude: tappedLocationCoord.longitude)
let ac = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
let deleteAction = UIAlertAction(title: "Delete Waypoint", style: .destructive) { (action) in
//some stuff
}
let insertAction = UIAlertAction(title: "Insert Waypoint After This", style: .default) { (action) in
//some stuff
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default) { (action) in
//some stuff
}//cancelAction
ac.addAction(deleteAction)
ac.addAction(insertAction)
ac.addAction(cancelAction)
//tried adding self, referencing parent - always error saying
//the object does not have a .present
mapView.present(ac, animated: true)
} else if control == view.rightCalloutAccessoryView {
//more of the same
}
}//annotationView
然后我删除了警报代码并添加了:
parent.userDefaultsManager.shouldShowAnnotationEditMenu.toggle()
并且我将通话画面更改为:
@ObservedObject var userDefaultsManager: UserDefaultsManager
var aTrip: Trip?
var body: some View {
VStack {
Text(aTrip?.name ?? "Unknown Map Name")
.padding(.top, -50)
.padding(.bottom, -20)
DetailMapView(aTrip: aTrip, userDefaultsManager: userDefaultsManager)
.padding(.top, -20)
.alert(isPresented: $userDefaultsManager.shouldShowAddress) {
//Alert(title: Text("\(aTrip?.name ?? "No") Address"),
Alert(title: Text(self.userDefaultsManager.approximateAddress),
message: Text("This is the approximate street address."),
dismissButton: .default(Text("Got it!")))
}//.alert shouldShowAddress
Text("This is the view where the trip information will be displayed.")
.multilineTextAlignment(.center)
.alert(isPresented: $userDefaultsManager.shouldShowAnnotationEditMenu) {
Alert(title: Text("Edit Annotations"),
message: Text("Choose this to insert an Annotation."),
dismissButton: .default(Text("Got it!")))
}//.alert shouldShowAddress
}
}
我想如果这安全的话我可以让它工作 - 但它看起来比它更复杂
应该是。
想法是这样的:
任何指导将不胜感激:Xcode版本 11.3.1 (11C504)
我为此花了一个小时,我是 SwiftUI 的新手,我跳进去只是为了回答一些简单的问题。
一种方法是使用 Bool
(@State
和 @Binding
)。
您还需要有一个 View
而不是直接在您的 SceneDelegate
中使用您的 UIViewRepresentable
。因为那是您链接 alert
.
的地方
像这样:
struct MainView: View {
@State var text = ""
@State var showingAlert: Bool
var body: some View {
VStack {
MapView(showingAlert: self.$showingAlert)
.alert(isPresented: $showingAlert) { () -> Alert in
print("SHOWING ALERT BODY: --> \($showingAlert.wrappedValue)")
return Alert(title: Text("Important message"), message: Text("Go out and have a girlfriend!"), dismissButton: .default(Text("Got it!")))
}
}
}
}
然后你的MapView
应该是这样的:
struct MapView: UIViewRepresentable {
let landmarks = LandmarkAnnotation.requestMockData()
@Binding var showingAlert: Bool
func makeCoordinator() -> MapViewCoordinator {
MapViewCoordinator(mapView: self, showingAlert: self.$showingAlert)
}
/**
- Description - Replace the body with a make UIView(context:) method that creates and return an empty MKMapView
*/
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context){
//If you changing the Map Annotation then you have to remove old Annotations
//mapView.removeAnnotations(mapView.annotations)
view.delegate = context.coordinator
view.addAnnotations(landmarks)
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView(showingAlert: Binding<Bool>.constant(true))
}
}
最后,在你的 MapViewCoordinator
中(我想你有这个 class,这是实现 MKMapViewDelegate
的委托方法的那个)。
/*
Coordinator for using UIKit inside SwiftUI.
*/
class MapViewCoordinator: NSObject, MKMapViewDelegate {
var mapViewController: MapView!
@Binding var showAlert: Bool
init(mapView: MapView, showingAlert: Binding<Bool>) {
self.mapViewController = mapView
self._showAlert = showingAlert
super.init()
}
func mapView(_ mapView: MKMapView, viewFor
annotation: MKAnnotation) -> MKAnnotationView?{
//Custom View for Annotation
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "customView")
annotationView.canShowCallout = true
//Your custom image icon
annotationView.image = UIImage(named: "locationPin")
return annotationView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
print("calloutAccessoryControlTapped")
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
print("didSelect")
self.showAlert = true
}
}
如您所见,我只是使用了 Bool 标志。尤其是 @Binding
那个。
是的,格伦。
这实际上是我做的方式。我用过ObservedObjects
。但是我认为您使用 @State
和 @Binding
的方法更好。
此外,我不想有条件地显示地图 - 只想显示注释连接。
出于某种原因,我无法对您的回答添加评论,因此在此处回复。
我有一个 SwiftUI 应用程序,其中有几个视图是使用 MapKit 制作的地图 UIViewRepresentable。我有兴趣点和使用的自定义注释 用于进一步操作的左右标注按钮。在右边我只是想要 显示有关航路点的信息。在左侧,我想发出警报 进一步操作的选择 - 例如,插入一个新的注释点。前 SwiftUI 我刚刚发出警报并执行了上述两项操作。但据我所知, UIViewRepresentable 版本上没有 self.present。因此我没有去过 能够显示警报。
只是为了实验 - 我将 SwiftUI 警报代码附加到 SwiftUI 视图 调用地图视图。使用 Observable 布尔值我确实可以引发这两个警报。 这对我来说似乎很奇怪,但也许是绑定到全局属性的警报代码 可以在任何地方。
我的第一次尝试:(结构是 DetailMapView)
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.leftCalloutAccessoryView {
guard let tappedLocationCoord = view.annotation?.coordinate else {return}
let tappedLocation = CLLocation(latitude: tappedLocationCoord.latitude, longitude: tappedLocationCoord.longitude)
let ac = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
let deleteAction = UIAlertAction(title: "Delete Waypoint", style: .destructive) { (action) in
//some stuff
}
let insertAction = UIAlertAction(title: "Insert Waypoint After This", style: .default) { (action) in
//some stuff
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default) { (action) in
//some stuff
}//cancelAction
ac.addAction(deleteAction)
ac.addAction(insertAction)
ac.addAction(cancelAction)
//tried adding self, referencing parent - always error saying
//the object does not have a .present
mapView.present(ac, animated: true)
} else if control == view.rightCalloutAccessoryView {
//more of the same
}
}//annotationView
然后我删除了警报代码并添加了:
parent.userDefaultsManager.shouldShowAnnotationEditMenu.toggle()
并且我将通话画面更改为:
@ObservedObject var userDefaultsManager: UserDefaultsManager
var aTrip: Trip?
var body: some View {
VStack {
Text(aTrip?.name ?? "Unknown Map Name")
.padding(.top, -50)
.padding(.bottom, -20)
DetailMapView(aTrip: aTrip, userDefaultsManager: userDefaultsManager)
.padding(.top, -20)
.alert(isPresented: $userDefaultsManager.shouldShowAddress) {
//Alert(title: Text("\(aTrip?.name ?? "No") Address"),
Alert(title: Text(self.userDefaultsManager.approximateAddress),
message: Text("This is the approximate street address."),
dismissButton: .default(Text("Got it!")))
}//.alert shouldShowAddress
Text("This is the view where the trip information will be displayed.")
.multilineTextAlignment(.center)
.alert(isPresented: $userDefaultsManager.shouldShowAnnotationEditMenu) {
Alert(title: Text("Edit Annotations"),
message: Text("Choose this to insert an Annotation."),
dismissButton: .default(Text("Got it!")))
}//.alert shouldShowAddress
}
}
我想如果这安全的话我可以让它工作 - 但它看起来比它更复杂 应该是。
想法是这样的:
任何指导将不胜感激:Xcode版本 11.3.1 (11C504)
我为此花了一个小时,我是 SwiftUI 的新手,我跳进去只是为了回答一些简单的问题。
一种方法是使用 Bool
(@State
和 @Binding
)。
您还需要有一个 View
而不是直接在您的 SceneDelegate
中使用您的 UIViewRepresentable
。因为那是您链接 alert
.
像这样:
struct MainView: View {
@State var text = ""
@State var showingAlert: Bool
var body: some View {
VStack {
MapView(showingAlert: self.$showingAlert)
.alert(isPresented: $showingAlert) { () -> Alert in
print("SHOWING ALERT BODY: --> \($showingAlert.wrappedValue)")
return Alert(title: Text("Important message"), message: Text("Go out and have a girlfriend!"), dismissButton: .default(Text("Got it!")))
}
}
}
}
然后你的MapView
应该是这样的:
struct MapView: UIViewRepresentable {
let landmarks = LandmarkAnnotation.requestMockData()
@Binding var showingAlert: Bool
func makeCoordinator() -> MapViewCoordinator {
MapViewCoordinator(mapView: self, showingAlert: self.$showingAlert)
}
/**
- Description - Replace the body with a make UIView(context:) method that creates and return an empty MKMapView
*/
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context){
//If you changing the Map Annotation then you have to remove old Annotations
//mapView.removeAnnotations(mapView.annotations)
view.delegate = context.coordinator
view.addAnnotations(landmarks)
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView(showingAlert: Binding<Bool>.constant(true))
}
}
最后,在你的 MapViewCoordinator
中(我想你有这个 class,这是实现 MKMapViewDelegate
的委托方法的那个)。
/*
Coordinator for using UIKit inside SwiftUI.
*/
class MapViewCoordinator: NSObject, MKMapViewDelegate {
var mapViewController: MapView!
@Binding var showAlert: Bool
init(mapView: MapView, showingAlert: Binding<Bool>) {
self.mapViewController = mapView
self._showAlert = showingAlert
super.init()
}
func mapView(_ mapView: MKMapView, viewFor
annotation: MKAnnotation) -> MKAnnotationView?{
//Custom View for Annotation
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "customView")
annotationView.canShowCallout = true
//Your custom image icon
annotationView.image = UIImage(named: "locationPin")
return annotationView
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
print("calloutAccessoryControlTapped")
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
print("didSelect")
self.showAlert = true
}
}
如您所见,我只是使用了 Bool 标志。尤其是 @Binding
那个。
是的,格伦。
这实际上是我做的方式。我用过ObservedObjects
。但是我认为您使用 @State
和 @Binding
的方法更好。
此外,我不想有条件地显示地图 - 只想显示注释连接。
出于某种原因,我无法对您的回答添加评论,因此在此处回复。