[英]SwiftUI Map Overlays without UIViewRepresentable
I try to create Map view with annotations and overlays using only iOS 14 SwiftUI Map.我尝试使用仅使用 iOS 14 SwiftUI Z46F3EA056CAA3026B91FEA3F7 I managed to create annotations but I am not able to create visible overlays because of lack of MKOverlayRenderer from MKMapView delegate.
我设法创建了注释,但由于 MKMapView 委托缺少 MKOverlayRenderer,我无法创建可见的叠加层。 How can I attach to Map view delegate so it can run its method
如何附加到 Map 视图委托,以便它可以运行其方法
Map(coordinateRegion: $region, showsUserLocation: true, userTrackingMode: $userTrackingMode, annotationItems: annotations)) { annotation in
MapAnnotation(coordinate: CLLocationCoordinate2DMake(annotation.latitude, annotation.longitude),
anchorPoint: CGPoint(x: 0.5, y: 0.7)) {
NavigationLink(destination: DetailsView()) {
VStack {
Image(systemName: "mappin")
.font(.title)
.foregroundColor(.red)
Text(annotation.name.split(separator: " ").joined(separator: "\n"))
.font(.caption)
.bold()
.multilineTextAlignment(.center)
.foregroundColor(.black)
.padding(2)
.background(RoundedRectangle(cornerRadius: 4).fill(Color.white.opacity(0.8)))
.layoutPriority(1)
}
}
}
}
.addOverlays(mapOverlays, delegate: mapDelegate)
and Map extension method:和 Map 扩展方法:
extension Map {
func addOverlays(_ overlays: [MKOverlay], delegate: MKMapViewDelegate) -> some View {
// MKMapView.appearance().delegate = delegate // THIS DOES NOT WORK AT ALL
MKMapView.appearance().addOverlays(overlays)
return self
}
}
and delegate:并委托:
class MapDelegate: NSObject, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKCircle {
let circle = MKCircleRenderer(overlay: overlay)
circle.strokeColor = .systemRed
circle.fillColor = .systemRed
circle.alpha = 0.2
circle.lineWidth = 1
return circle
}
return MKOverlayRenderer()
}
}
Definitely not possible, SwiftUI Map does not yet support overlays.绝对不可能,SwiftUI Map 还不支持覆盖。 Using UIViewRepresentsable is easy, see SO example here:
使用 UIViewRepresentsable 很容易,请参见此处的示例:
Swiftui how to use MKOverlayRenderer? Swiftui 如何使用MKOverlayRenderer? using the following code:
使用以下代码:
struct MapView: UIViewRepresentable {
@Binding var route: MKPolyline?
let mapViewDelegate = MapViewDelegate()
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
view.delegate = mapViewDelegate // (1) This should be set in makeUIView, but it is getting reset to `nil`
view.translatesAutoresizingMaskIntoConstraints = false // (2) In the absence of this, we get constraints error on rotation; and again, it seems one should do this in makeUIView, but has to be here
addRoute(to: view)
}
}
private extension MapView {
func addRoute(to view: MKMapView) {
if !view.overlays.isEmpty {
view.removeOverlays(view.overlays)
}
guard let route = route else { return }
let mapRect = route.boundingMapRect
view.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), animated: true)
view.addOverlay(route)
}
}
class MapViewDelegate: NSObject, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.fillColor = UIColor.red.withAlphaComponent(0.5)
renderer.strokeColor = UIColor.red.withAlphaComponent(0.8)
return renderer
}
}
Probably this is a pretty late answer, but could be useful to someone else.可能这是一个很晚的答案,但可能对其他人有用。
After trying a few approaches, I came to this solution (btw, I would say that's not even close to a fancy code... but it works) .在尝试了几种方法之后,我找到了这个解决方案(顺便说一句,我会说这甚至不接近花哨的代码......但它确实有效) 。
First, you have to create a class that implements the MKMapViewDelegate
(in my case I needed to show an overlay with a custom theme on the Map
, but you can use it to show a Polyline or a Polygon as well).首先,您必须创建一个实现
MKMapViewDelegate
的 class (在我的情况下,我需要在Map
上显示具有自定义主题的叠加层,但您也可以使用它来显示折线或多边形)。
class MapCustomDelegate: NSObject, MKMapViewDelegate {
var parent: MKMapView
init(_ parent: MKMapView) {
self.parent = parent
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let tileOverlay = overlay as? MKTileOverlay {
let renderer = MKTileOverlayRenderer(overlay: tileOverlay)
return renderer
}
return MKOverlayRenderer()
}
}
Then in the view you have to implement the delegate using the MKMapView.appearance()
instance, like this:然后在视图中,您必须使用
MKMapView.appearance()
实例来实现委托,如下所示:
struct MapCustomView: View {
// Properties
@StateObject private var viewModel: MapViewModel = MapViewModel()
private let mapAppearanceInstance = MKMapView.appearance()
private var mapCustomDelegate: MapCustomDelegate = MapCustomDelegate(MKMapView.appearance())
..
var body: some View {
VStack {
Map(coordinateRegion: $viewModel.mapRegion,
annotationItems: viewModel.items) { item in
MapAnnotation(coordinate: item.location) {
..
}
}
.onAppear {
// viewModel.mapOverlay -> MKTileOverlay
self.mapAppearanceInstance.delegate = mapCustomDelegate
self.mapAppearanceInstance.addOverlay(viewModel.mapOverlay)
}
}
}
And it should work.它应该工作。 Hope this helps:)
希望这可以帮助:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.