ios - 没有 UIViewAnimationOptionBeginFromCurrentState,UIView 动画无法工作

标签 ios iphone objective-c animation uiview

我遇到了一个奇怪的bug(或者我真的很笨……): 我想在 MKAnnotationView 中显示自定义标注。 我正在做的是添加一个自定义 View 作为 MKAnnotationView 的 subview 。 我在添加动画时遇到问题。

我有一个 MKMapView,我的 View Controller 作为委托(delegate)

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)annotationView
{
    [self.calloutViewController setCalloutState:CalloutStateNormal
                                       animated:YES
                                 annotationView:annotationView
                                     completion:NULL];
}

- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)annotationView
{
    [self.calloutViewController setCalloutState:CalloutStateHidden
                                       animated:YES
                                 annotationView:annotationView
                                     completion:NULL];
}

self.calloutViewController 是一个自定义 View Controller ,它创建一个气泡形状的 View (只需添加圆角和白色背景)。

- (void)setCalloutState:(CalloutState)calloutState
               animated:(BOOL)animated
         annotationView:(MKAnnotationView *)annotationView
             completion:(void (^)(BOOL finished))completion
{
    if (self.view.superview == annotationView || !annotationView) {

    } else {
//        [self.view.layer removeAllAnimations];
        [self.view removeFromSuperview];

        self.view.transform = CGAffineTransformIdentity;
        self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
        self.view.transform = CGAffineTransformMakeScale(0, 0);
        self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);

        [annotationView addSubview:self.view];
    }

    void (^animationBlock)(void) = ^{
        self.view.transform = CGAffineTransformIdentity;

        switch (calloutState) {
            case CalloutStateHidden:
                self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
                self.view.transform = CGAffineTransformMakeScale(0, 0);
                break;
            case CalloutStateNormal:
                self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
                break;
            case CalloutStateExpanded:
                self.view.bounds = CGRectMake(0, 0, expandedViewWidth, expandedViewHeight);
                break;
            default:
                break;
        }

        self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);

        [self.view layoutIfNeeded];
    };

    if (animated) {
        // TODO: figure out why the first animateWithDuration is needed in this nested thing
        [UIView animateWithDuration:0
                              delay:0
                            options:UIViewAnimationOptionBeginFromCurrentState
                         animations:NULL
                         completion:^(BOOL finished) {

                             [UIView animateWithDuration:0.3
                                                   delay:0
                                                 options:UIViewAnimationOptionBeginFromCurrentState
                                              animations:animationBlock
                                              completion:^(BOOL finished) {
                                                  if (finished) {
                                                      self.calloutState = calloutState;

                                                      // TODO: figure out how to end UIView animation instantly so we don't need the second condition at the if
                                                      // having a concurrency problem here
                                                      if (calloutState == CalloutStateHidden && self.view.superview == annotationView) {
                                                          [self.view removeFromSuperview];
                                                      }

                                                      self.editingEnabled = calloutState == CalloutStateExpanded;
                                                  }

                                                  if (completion) {
                                                      completion(finished);
                                                  }
                                              }];

                         }];
        // ---------------------------------------------------------------------------------
    } else {
        animationBlock();

        self.calloutState = calloutState;
        if (calloutState == CalloutStateHidden) {
            [self.view removeFromSuperview];
        }

        self.editingEnabled = calloutState == CalloutStateExpanded;

        if (completion) {
            completion(YES);
        }
    }
}

问题是: - 如果我在 map 上选择一个图钉 (MKAnnotationView),它会正确显示我创建的标注气泡。 - 之后,我点击了另一个图钉(最后一个图钉上仍然显示气泡)。 - 然后使用选项 1) 标注气泡只是从一个图钉跳到另一个图钉,而不对其比例进行动画处理。 - 使用选项 2) 它可以正常工作。

我想了解为什么选项 1) 不起作用。 我不认为这应该有任何区别,因为当我点击第二个图钉时没有动画发生。

提前致谢。

编辑: 为了简化起见,我创建了一个项目,其中包含重现我的问题所需的最少代码:

@interface TestViewController () <MKMapViewDelegate>

@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@property (strong, nonatomic) UIView *customCallout;

@end

@implementation TestViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.customCallout = [[UIView alloc] initWithFrame:CGRectMake(-50, -50, 100, 50)];
    self.customCallout.backgroundColor = [UIColor colorWithWhite:1 alpha:0.7];

    self.mapView.delegate = self;

    CustomAnnotation *annoation1 = [CustomAnnotation new];
    annoation1.coordinate = CLLocationCoordinate2DMake(40, -100);
    [self.mapView addAnnotation:annoation1];

    CustomAnnotation *annoation2 = [CustomAnnotation new];
    annoation2.coordinate = CLLocationCoordinate2DMake(40, -90);
    [self.mapView addAnnotation:annoation2];
}

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    [self.customCallout removeFromSuperview];
    self.customCallout.transform = CGAffineTransformMakeScale(0, 0);
    [view addSubview:self.customCallout];

//    [UIView animateWithDuration:0
//                          delay:0
//                        options:UIViewAnimationOptionBeginFromCurrentState
//                     animations:NULL
//                     completion:^(BOOL finished) {
                         [UIView animateWithDuration:1
                                               delay:0
                                             options:UIViewAnimationOptionBeginFromCurrentState
                                          animations:^{
                                              self.customCallout.transform = CGAffineTransformIdentity;
                                          }
                                          completion:NULL];
//                     }];
}

@end

就像以前一样,第一次点击一个注释时,它工作正常,但是当你点击第二个注释时,动画不会发生。如果您取消注释注释代码,它工作正常。

最佳答案

UIViewAnimationOptionBeginFromCurrentState 从当前状态在屏幕上绘制开始动画,而不是从属性的当前值开始。因此,即使 View 的 transform 属性的值为 Scale(0, 0),它还没有将其绘制到屏幕上。额外的动画 block 有所不同的原因是,即使持续时间为 0,完成也不会立即执行,而是在下一次通过运行循环时执行,这为 View 提供了足够的时间来绘制自己。

如果删除 UIViewAnimationOptionBeginFromCurrentState 选项,动画将按预期工作:

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    [self.customCallout removeFromSuperview];
    self.customCallout.transform = CGAffineTransformMakeScale(0, 0);
    [view addSubview:self.customCallout];
    [UIView animateWithDuration:1 animations:^{
        self.customCallout.transform = CGAffineTransformIdentity;
    }];
}

关于ios - 没有 UIViewAnimationOptionBeginFromCurrentState,UIView 动画无法工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22543431/

相关文章:

iOS - 什么是分配泄漏?

ios - 如何自动实现 Properties 和 ivars 的 NSCoding

iphone - 如何在标签中增加 NSTimer 的时间?

ios - Swift:如何将字符串列表转换为 CGPoint 列表?

iOS 开发者和分发证书

iphone - UIView背景图片透明度问题

ios - Xcode 5 "error: can' t exec 'codesign'(没有这样的文件或目录)”

iphone - 如何使UIPickerView像UIDatePicker一样?

ios - 检查用户是否连接到他的 Apple 帐户,如果没有,请他连接到它

ios - 如何让应用不频繁地在后台搜索重大更新?