9

我有一个MKMapView. annotation pins当视图被加载时,最近的 pin 被搜索并且地图将被缩放,因此它同时显示用户的位置和最近的 pin。我用[map setRegion:region animated:YES];. 到目前为止一切正常。同样的方法也可以通过点击一个按钮来调用,该按钮可以定位用户,然后完全按照我刚才描述的方式进行操作。

我还有一个搜索字段,用户可以使用它搜索地图点。当用户点击其中一个搜索结果时,地图会设置区域,因此搜索到的图钉位于中间。现在,这有点奇怪。我还设置了这个区域动画,至少我执行与上面相同的命令。但是,如果地图点离地图的当前可见部分太远,则在更改区域时不会显示动画。我错过了什么吗?我已经看过Apples docs,他们没有提到任何关于动画最大距离的内容。

我期待着任何帮助!


更新 1:
刚刚在模拟器中再次测试。一个有趣的事实是,当我第一次搜索MapPoint然后选择一个搜索结果时,它没有动画。如果我在第一个搜索之后执行另一个搜索并选择一个结果,它会生成动画。一旦我点击定位按钮,它会将用户带回他的位置和最近的点,它不会为此设置动画setRegion:以及之后的第一次搜索。但仅在模拟器中,在我的 4S 上,它完全符合我在上面原始问题中的描述。


更新 2:
在评论中,我被要求提供示例坐标。
所以这里是第一步的坐标(搜索自己的位置和最近的pin):
My Location: 47.227131 / 8.264251
Nearest pin: 47.251347 / 8.357191
它们之间的距离大约是22公里。地图的中心是两个图钉之间的中心。从中心到屏幕边界的距离是两点之间距离的 1.5 倍,在这种情况下约为 33 公里。
这里是第二步的一组坐标(搜索一个地图点并选择它):
搜索到的 pin: 46.790680 / 9.818824
到屏幕边界的距离在这里固定为 500 米。

4

5 回答 5

14

我已经在 iOS 6 和 iOS 7 beta 上使用一个简单的演示应用程序测试了这个问题。事实证明,地图视图实际上并不总是动画区域之间的过渡。这取决于区域之间的距离。例如,从巴黎到伦敦的过渡没有动画效果。但如果你先缩小一点,然后去伦敦,它就会变成动画。

文档说:

动画:如果您希望地图视图以动画方式过渡到新区域,请指定 YES,如果您希望地图立即以指定区域为中心,请指定 NO。

但正如我们所见,我们不能依赖动画。我们只能告诉地图视图过渡应该是动画的。MapKit 决定动画是否合适。它告诉代理过渡是否将在-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated.

为了在所有情况下始终如一地为区域变化设置动画,您需要首先为中间区域设置动画。设 A 为当前地图区域,B 为目标区域。如果区域之间有交集,您可以直接过渡。(将 转换MKCoordinateRegion为 anMKMapRect并用于MKMapRectIntersection查找交点)。如果没有交集,则计算跨越两个区域的区域 C(使用MKMapRectUnionMKCoordinateRegionForMapRect)。然后先去C区,regionDidChangeAnimated再去B区。

示例代码:

MKCoordinateRegion region = _destinationRegion;    
MKMapRect rect = MKMapRectForCoordinateRegion(_destinationRegion);
MKMapRect intersection = MKMapRectIntersection(rect, _mapView.visibleMapRect);
if (MKMapRectIsNull(intersection)) {
    rect = MKMapRectUnion(rect, _mapView.visibleMapRect);
    region = MKCoordinateRegionForMapRect(rect);
    _intermediateAnimation = YES;
}
[_mapView setRegion:region animated:YES];

-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    if (_intermediateAnimation) {
        _intermediateAnimation = NO;
        [_mapView setRegion:_destinationRegion animated:YES];
    }
}

这个辅助方法取自这里

MKMapRect MKMapRectForCoordinateRegion(MKCoordinateRegion region)
{
    MKMapPoint a = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
                                                                      region.center.latitude + region.span.latitudeDelta / 2,
                                                                      region.center.longitude - region.span.longitudeDelta / 2));
    MKMapPoint b = MKMapPointForCoordinate(CLLocationCoordinate2DMake(
                                                                      region.center.latitude - region.span.latitudeDelta / 2,
                                                                      region.center.longitude + region.span.longitudeDelta / 2));
    return MKMapRectMake(MIN(a.x,b.x), MIN(a.y,b.y), ABS(a.x-b.x), ABS(a.y-b.y));
}

WWDC 2013 session 309 Putting Map Kit in Perspective解释了如何在 iOS 7 中进行如此复杂的转换。

于 2013-06-28T11:18:05.330 回答
1

我也有这个问题,它并不总是动画,有时它只是跳跃和溶解。但是,我注意到,如果您为camera而不是region设置动画,它会始终保持动画。

但是使用相机,您必须设置眼睛距离/高度而不是纬度/经度跨度。对于下面的粗略计算,我有一个简单的计算,它基本上只是将高度(以米为单位)设置为与该地区的经度跨度相同的米数。如果您想要精确的精度,您必须计算出该地区纬度每度的米数,由于地球不是一个完美的球体,因此略有变化。当然,您可以乘以该值来扩大或缩小范围以品尝。

斯威夫特 4.1示例代码:

/* -------------------------------------------------------------------------- */
func animateToMapRegion(_ region: MKCoordinateRegion) {
    // Quick and dirty calculation of altitude necessary to show region.
    // 111 kilometers per degree longitude.
    let metersPerDegree: Double = 111 * 1_000
    let altitude = region.span.longitudeDelta * metersPerDegree

    let camera = MKMapCamera(lookingAtCenter: region.center, fromEyeCoordinate: region.center, eyeAltitude: altitude)

    self.mapView.setCamera(camera, animated: true)
}
于 2018-05-03T22:38:48.783 回答
1

您只需获取当前位置,然后调用此函数:

import MapKit

var appleMapView = MKMapView()

var currentCoordinate: CLLocationCoordinate2D?

currentCoordinate 必须是您当前的位置坐标:

 ◙ if let currentLoc = self.currentCoordinate {
        let center = CLLocationCoordinate2D(latitude: currentLoc.latitude, longitude: currentLoc.longitude)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
        appleMapView.setRegion(region, animated: true)
    }
于 2020-11-27T13:47:45.287 回答
1

以下是@Felix 重写为 Swift 4 的函数:

// MARK: - MapView help properties
var destinationRegion: MKCoordinateRegion?
var intermediateAnimation = false

func center() {
    // Center map
    var initialCoordinates = CLLocationCoordinate2D(latitude: 49.195061, longitude: 16.606836)
    var regionRadius: CLLocationDistance = 5000000

    destinationRegion = MKCoordinateRegionMakeWithDistance(initialCoordinates, regionRadius * 2.0, regionRadius * 2.0)
    centreMap(on: destinationRegion!)
}


private func mapRect(forCoordinateRegion region: MKCoordinateRegion) -> MKMapRect {
    let topLeft = CLLocationCoordinate2D(latitude: region.center.latitude + (region.span.latitudeDelta/2), longitude: region.center.longitude - (region.span.longitudeDelta/2))
    let bottomRight = CLLocationCoordinate2D(latitude: region.center.latitude - (region.span.latitudeDelta/2), longitude: region.center.longitude + (region.span.longitudeDelta/2))

    let a = MKMapPointForCoordinate(topLeft)
    let b = MKMapPointForCoordinate(bottomRight)

    return MKMapRect(origin: MKMapPoint(x:min(a.x,b.x), y:min(a.y,b.y)), size: MKMapSize(width: abs(a.x-b.x), height: abs(a.y-b.y)))
}


func centreMap(on region: MKCoordinateRegion) {
    var region = region
    var rect = mapRect(forCoordinateRegion: region)
    let intersection = MKMapRectIntersection(rect, mapView.visibleMapRect)

    if MKMapRectIsNull(intersection) {
        rect = MKMapRectUnion(rect, mapView.visibleMapRect)
        region = MKCoordinateRegionForMapRect(rect)
        intermediateAnimation = true
    }

    mapView.setRegion(region, animated: true)
}

// MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    if intermediateAnimation, let region = destinationRegion {
        intermediateAnimation = false
        mapView.setRegion(region, animated: true)
    }
}
于 2017-12-09T16:46:11.697 回答
0

对于任何有相同问题并使用 Swift 并使用 tableView 的人:

我在关闭 tableView 后调用了 setRegion,它没有显示动画。这是我编辑前的代码:

dismiss(animated: true, completion: nil)
a function that calls setRegion

然后我将其更改为:

dismiss(animated: true, completion: {
        a function that calls setRegion
    })

这次它起作用了。

于 2017-10-15T22:57:35.167 回答