在屏幕外渲染 MKMapView

Render MKMapView offscreen

我正在尝试将 MKMapView 渲染为 UIImage,但不在屏幕上显示。我初始化地图:

let mapView = MKMapView(frame: CGRect(x: 0, y: 0, width: 1000, height: 1000))
mapView.delegate = self

let region = MKCoordinateRegionMakeWithDistance(location.coordinate(), 1000, 1000)
mapView.setRegion(region, animated: false)

我也实现了MKMapKitDelegate的方法mapViewDidFinishLoadingMap()。此方法永远不会被调用,除非我将地图添加到视图层次结构并且使其可见。这意味着将其 alpha 设置为 0,或将 isHidden 设置为 true 不起作用(在这种情况下地图不会加载)。帮忙?

你能说说你隐藏的目的是什么吗?如果您的图像不可见,地图将不会加载数据,这就是为什么它的委托没有被调用的原因,正如苹果文档中提到的那样,请参阅下面的描述。它说在你的情况下加载当前请求时将调用它我认为地图不可见因此它的请求未加载并且当你使其可见时请求被加载因此你可以看到。

This method is called when the map tiles associated with the current request have been loaded. Map tiles are requested when a new visible area is scrolled into view and tiles are not already available. Map tiles may also be requested for portions of the map that are not currently visible. For example, the map view may load tiles immediately surrounding the currently visible area as needed to handle small pans by the user.

https://developer.apple.com/reference/mapkit/mkmapviewdelegate/1452291-mapviewdidfinishloadingmap

显然,MKMapView 仅加载地图的可见图块,因此您要离线渲染的 mapView 必须是“可见的”。
据我所知,一个视图是“可见的”,如果它的 window 属性 被设置,即不是 nil(参见 progrmr 的回答 here ).
因此,一种可能性是设置一个额外的 UIWindow,将您的 mapView 作为根视图。在这种情况下,您的 mapViewwindow 属性 已设置,我相信 mapView 会加载所需的图块,以便可以渲染,即使额外的 UIWindow 不可见.
这显然是由 pageViewController 完成的,请参阅上面 link 中 evanflash 的评论。

好的,这是我自己的解决方案。

  1. 实施MKMapViewDelegate方法mapViewDidFinishRenderingMap(_ mapView:, fullyRendered:)。请务必使用此方法而不是 mapViewDidFinishLoadingMap(_ mapView:)!

  2. 这是古怪的部分。将您的地图视图添加到现有的可见视图(我使用视图控制器自己的视图),并将其放置在屏幕外,只显示一个像素。这很重要,因为如果地图没有可见像素,它就不会呈现。例如:

    let width = 1000
    let height = 1000
    
    let mapView = MKMapView(frame: CGRect(x: -width+1, y: -height+1, width: width, height: height))
    view.addSubview(mapView)
    
  3. 没有第 3 步。如果您正确配置地图,将调用 (1) 中提到的委托方法,此时您将拥有完全渲染的地图。

我上周遇到了这个问题,因为我嵌入了 MapView 在 Stackview 中,因此当设置为 hidden 时它会 自动 减少。也许不是你的情况,但你应该为你的 mapView 检查 Size

此外,在我用另一个替换 StackView 之前,将 alpha 设置为接近零的值 - 而不是使用 hidden- 确实有所帮助(未检查为零)。