控制iOS6中MKMapView动画速度

8

我正在尝试在地图视图上跟踪一辆汽车。

这段代码应该以相同的速度动画显示汽车和地图,以便注释视图始终出现在中心位置:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration: 1.0];
[UIView setAnimationBeginsFromCurrentState:YES];

[car setCoordinate:coord];
[mapView setCenterCoordinate:coord];

[UIView commitAnimations];

在iOS 5中工作得很好,在iOS 6中地图不再动画,但汽车确实会动画。

我尝试过[mapView setCenterCoordinate:co animated:YES],但我不能控制动画速度。它将始终以默认持续时间(0.2秒)进行动画。


尝试使用 [mapView setCenterCoordinate:co animated:NO]; - user207616
@relikd 我尝试了,这与 [mapView setCenterCoordinate:co] 有相同的效果。 - Felix
3个回答

11

今天我遇到了同样的问题。我认为问题不在于MKMapView,而是iOS6处理动画的(新)方式。

似乎在iOS6中,如果一个动画在先前的动画完成之前发生(取决于运行循环),则旧动画会被新动画中断。我认为只有在“beginsFromCurrentState”选项或属性(根据您是否使用基于块的动画)被新动画所使用时才会发生这种情况。

为了确保,我认为您应该尝试使用基于块的动画来查看您的动画是否真的被另一个动画打断了。

这段代码应该与您的代码等效,并允许您查看您的动画是否已被中断或取消(如果“finished”为false):

[UIView animateWithDuration:1.0 delay:0.0f options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionBeginFromCurrentState) animations:^{

    [car setCoordinate:coord];
    [mapView setCenterCoordinate:coord];

} completion:^(BOOL finished){
    NSLog(@"has not been interrupted : %d", finished);
}];

(在iOS < 6中,“finished”应该为true…)

在我的情况下,似乎我的动画被以下UIViewController的方法所打断了,这些方法由系统在动画块中执行,打断了我的动画链:

- (void)viewWillAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;

抱歉,那不能帮助我。我已经尝试过使用基于块的UIView动画(使用和不使用 UIViewAnimationOptionBeginFromCurrentState)。无论我做什么,我都无法控制地图视图本身的动画速度,而且 finished 标志总是 YES,因为我每3秒进行一次动画,而动画持续时间较短(1秒),所以它不会被中断。 - Felix
1
+1 是因为它很有信息量,但并没有解决问题。 - AlexWien
你能否将地图中心动画化延迟1秒钟呢? - AlexWien

7

我发现如果按照以下格式编写,标准的UIView AnimationWithDuration就会生效:

// create a region with a center coordinate and a degree span
let center = CLLocationCoordinate2D(latitude: 42.3601, longitude: -71.0689)
let span = MKCoordinateSpanMake(1.0, 1.0)
let region = MKCoordinateRegion(center: center, span: span)

UIView.animateWithDuration(3.0,
             delay: 0.0,
           options: .CurveEaseInOut | .AllowUserInteraction,
        animations: {
                    self.mapView.setRegion(region, animated: true);
        },
        completion: { finished in
                    println("completed 3 second animation to new region")
        })

希望这对你也有用! :)
(注:有人指出,此回答是针对iOS7/8的,而问题是针对iOS6的。)
而且,这个简单的方法实际上也可以正常工作...
    let c = mkMap.userLocation.coordinate
    let r = CLLocationDistance( 1500 )
    let cr = MKCoordinateRegionMakeWithDistance( c, r, r )

    UIView.animate(withDuration: 1.4, animations: { [weak self] in

        self?.mkMap.setRegion( cr, animated: true)
    })

这个问题是针对iOS 6的。我敢打赌你没有在iOS 6上测试过它,因为Swift代码无法在旧版本的iOS上运行。 - Felix
1
啊,是的,我应该更仔细地阅读。(我要注意这是iOS 7/8安全的) - jbobrow

4

在 iOS 6 中,使用 MKMapView 中的这些方法时,似乎无法控制动画速度:

- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated;
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;
- (void)setVisibleMapRect:(MKMapRect)mapRect animated:(BOOL)animate;
- (void)setVisibleMapRect:(MKMapRect)mapRect edgePadding:(UIEdgeInsets)insets animated:(BOOL)animate;

然而,我发现了一个有持续时间参数的私有方法。因此,我通过子类化MKMapView并覆盖该私有方法(仅存在于iOS6中)来解决了我的问题:

MyMapView.h

#import <MapKit/MapKit.h>

@interface MyMapView : MKMapView

@property(nonatomic) BOOL overridesAnimationDuration;
@property(nonatomic) NSTimeInterval mapAnimationDuration;

@end

MyMapView.m

@interface MKMapView (Private)
- (void)_setZoomScale:(float)scale centerMapPoint:(CLLocationCoordinate2D)center duration:(double)d animationType:(int)animType;
@end

@implementation MyMapView
- (void)_setZoomScale:(float)scale centerMapPoint:(CLLocationCoordinate2D)center duration:(double)d animationType:(int)animType
{
    if (_overridesAnimationDuration) {
        d = _mapAnimationDuration;
    }
    [super _setZoomScale:scale centerMapPoint:center duration:d animationType:animType];
}    
@end

我添加了两个属性,允许您覆盖默认的动画时间。要使用它,请在区域更改之前设置overridesAnimationDuration为YES,将mapAnimationDuration设置为所需的持续时间,并在委托调用mapView:regionWillChangeAnimated:中将overridesAnimationDuration切换为NO。

请注意,这可能在未来的iOS版本中无法正常工作,因为它是私有API。苹果可以删除或更改此方法。


2
@jfisk 我不知道,但是使用这段代码的三个应用程序更新已经顺利通过了审批。 - Felix
我在iPhone上用iOS5测试了你的代码。重写的方法也被调用了。 - AlexWien
调用[setCenterCoordinate:animated]方法可以实现目标,但是动画类型似乎是EaseInEaseOut,这对于此任务并不理想。您使用[setCenterCoordinate:animated]还是动画块? - AlexWien
你对这个解决方案满意吗?在iOS5中它的效果更好。当用户想要捏合缩放时,你能否停止动画? - AlexWien
我发现将动画持续时间设置为高于0.2的值会降低捏合缩放或平移手势的成功率。将其设置为0.5有时可以缩放,将其设置为0.9则会忽略缩放和平移手势。你解决了这个问题吗? - AlexWien
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接