MKMapView setRegion动画不显示动画

时间:2013-04-16 15:32:11

标签: iphone ios objective-c mkmapview

我有MKMapView annotation pins。加载视图时,将搜索最近的引脚,并且地图将进行缩放,以便显示用户的位置和最近的引脚。我用[map setRegion:region animated:YES];做到了。到目前为止一切正常。也可以通过点击定位用户的按钮来调用相同的方法,然后完成我刚才描述的操作。

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

我期待着任何帮助!


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


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

5 个答案:

答案 0 :(得分:13)

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

文档说:

  

动画:如果您希望地图视图为其设置动画,请指定YES   如果您希望地图居中,请转换到新地区或否   立即指定区域。

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

为了在所有情况下始终为区域变化设置动画,您需要先设置中间区域的动画。设A为当前地图区域,B为目标区域。如果区域之间存在交叉,则可以直接转换。 (将MKCoordinateRegion转换为MKMapRect并使用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];
    }
}

此辅助方法取自here

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会议309 将Map Kit放入透视解释了如何在iOS 7中进行此类复杂转换。

答案 1 :(得分: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)
    }
}

答案 2 :(得分:1)

我也有这个问题,它不会总是动画,有时它只会跳跃和溶解。但是,我注意到如果您为相机而不是区域设置动画,它会一直动画。

但是使用相机时,您必须设置眼距/高度而不是纬度/经度。我有一个简单的计算,下面是粗略的,它基本上只是将高度(以米为单位)设置为与该区域的经度跨度相同的米数。如果你想要精确的准确度,你必须计算出该区域纬度的每度数米数,这个数字会略有变化,因为地球不是一个完美的球体。当然,您可以将该值乘以扩大或缩小视图以进行品味。

Swift 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)
}

答案 3 :(得分:1)

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

f = [] a = [] for i in range(10): a.append(i) f.append(list(a)) #amended line a.clear() >>>print(f) [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9]]

import MapKit

var appleMapView = MKMapView()

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

 var currentCoordinate: CLLocationCoordinate2D?

答案 4 :(得分:0)

对于拥有相同问题且正在使用Swift且正在使用tableView的任何人:

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

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

然后我把它改为:

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

这次它有效。