swift - 在主(ContentView)SwiftUI 视图中以 UIViewRepresentable 的形式访问 MKMapView 元素
问题描述
我正在使用 SwiftUI 显示地图,如果用户点击注释,它会在 VStack 中弹出一个详细视图。我已经制作了地图视图并在另一个 SwiftUI 文件中插入了注释。我还做了详细视图。
如何在主视图文件中访问该地图的注释以定义 .tapaction 以便他们将其用于详细视图?
我尝试将视图定义为 MKMapView,但无法为另一个 SwiftUI 视图中的 UIViewRepresentable 执行此操作。
主视图(ContentView)代码为:
struct ContentView: View {
@State private var chosen = false
var body: some View {
VStack {
MapView()
.edgesIgnoringSafeArea(.top)
.frame(height: chosen ? 600:nil)
.tapAction {
withAnimation{ self.chosen.toggle()}
}
if chosen {
ExtractedView()
}
}
}
}
地图视图代码是:
struct MapView : UIViewRepresentable {
@State private var userLocationIsEnabled = false
var locationManager = CLLocationManager()
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
view.showsUserLocation = true
.
.
.
let sampleCoordinates = [
CLLocation(latitude: xx.xxx, longitude: xx.xxx),
CLLocation(latitude: xx.xxx, longitude: xx.xxx),
CLLocation(latitude: xx.xxx, longitude: xx.xxx)
]
addAnnotations(coords: sampleCoordinates, view: view)
}
}
}
我希望能够访问地图视图注释并在另一个视图中定义点击操作。
解决方案
在 SwiftUI DSL 中,您不能访问视图。
相反,您可以组合它们的“表示”来创建视图。
一个大头针可以用一个对象来表示——操作大头针也会更新地图。
这是我们的 pin 对象:
class MapPin: NSObject, MKAnnotation {
let coordinate: CLLocationCoordinate2D
let title: String?
let subtitle: String?
let action: (() -> Void)?
init(coordinate: CLLocationCoordinate2D,
title: String? = nil,
subtitle: String? = nil,
action: (() -> Void)? = nil) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.action = action
}
}
Here's my Map
,它不仅是UIViewRepresentable
,而且还使用了Coordinator
.
(更多关于UIViewRepresentable
和协调者可以在优秀的 WWDC 2019 演讲中找到 -集成 SwiftUI)
struct Map : UIViewRepresentable {
class Coordinator: NSObject, MKMapViewDelegate {
@Binding var selectedPin: MapPin?
init(selectedPin: Binding<MapPin?>) {
_selectedPin = selectedPin
}
func mapView(_ mapView: MKMapView,
didSelect view: MKAnnotationView) {
guard let pin = view.annotation as? MapPin else {
return
}
pin.action?()
selectedPin = pin
}
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
guard (view.annotation as? MapPin) != nil else {
return
}
selectedPin = nil
}
}
@Binding var pins: [MapPin]
@Binding var selectedPin: MapPin?
func makeCoordinator() -> Coordinator {
return Coordinator(selectedPin: $selectedPin)
}
func makeUIView(context: Context) -> MKMapView {
let view = MKMapView(frame: .zero)
view.delegate = context.coordinator
return view
}
func updateUIView(_ uiView: MKMapView, context: Context) {
uiView.removeAnnotations(uiView.annotations)
uiView.addAnnotations(pins)
if let selectedPin = selectedPin {
uiView.selectAnnotation(selectedPin, animated: false)
}
}
}
这个想法是:
- 引脚位于
@State
包含地图的视图上,并作为绑定向下传递。 - 每次添加或删除 pin 时,都会触发 UI 更新 - 所有 pin 都将被删除,然后再次添加(效率不是很高,但这超出了此答案的范围)
- 这
Coordinator
是地图委托 - 我可以MapPin
从委托方法中检索触摸。
测试它:
struct ContentView: View {
@State var pins: [MapPin] = [
MapPin(coordinate: CLLocationCoordinate2D(latitude: 51.509865,
longitude: -0.118092),
title: "London",
subtitle: "Big Smoke",
action: { print("Hey mate!") } )
]
@State var selectedPin: MapPin?
var body: some View {
NavigationView {
VStack {
Map(pins: $pins, selectedPin: $selectedPin)
.frame(width: 300, height: 300)
if selectedPin != nil {
Text(verbatim: "Welcome to \(selectedPin?.title ?? "???")!")
}
}
}
}
}
...并尝试在英国伦敦缩放/点击图钉 :)
推荐阅读
- python - 获取窗口上的最小值并将其添加到 PostgreSQL 窗口中的所有值中
- go - 在 Golang 程序的另一个函数中时 GDB 看不到全局变量
- pandas - 安装pandas inn graalpython时遇到错误
- dbt - dbt中特定列数据的增量更新
- bash - bash `${qidpath##*/}` 中的`##*/` 是什么意思?
- javascript - 如何调试使用 webpack 编译的 npm 模块?
- python - 如果 Selenium 挂在 Celery 任务中并阻塞了整个 Celery 怎么办?
- c - C:在txt文件中搜索字符串并输出
- windows - 文本文件具有不同大小的边距
- javascript - 页面加载时如何使徽标从屏幕外滑入?