iOS layout animation ignores duration when fired o

2019-07-24 01:54发布

You can see the problem comparing two gifs below. Both "shrink" and "stretch" animation are based on constraints manipulation and [self layoutIfNedeed] is placed inside -animateWithDuration block. As you can see it works as intended when the map is not moving. But "shrink" animation happens instantly as you start dragging the map. If you look closely you might notice that cornerRadius animation still works. This tells me that it might have something to do with map (scrollView inside? no idea how google map works) calling it's own layout blocks that interfere with my animation. Or it might be due to the fact that cornerRadius animation is done using CABasicAnimation, not UIView animation.

Animated InfoView is not a subview of the mapView. Not sure if it should affect my infoView's layout when mapView is calling inner layout methods.

I've tried all the options combined UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionOverrideInheritedDuration | UIViewAnimationOptionOverrideInheritedOptions just to see if it helps. It does not.

I think I can overcome this manipulating frame directly instead of manipulating constraints and it will look the same to the user, but I feel like using constraints is so much more elegant. I try to avoid manipulating frames as much as possible and use autolayout.

Any ideas what's causing this and how to overcome this problem using autolayout animation?

UPDATE

I've tried animating frame directly - result is the same. So it has nothing to do with autolayout. It seems like current view animation is stopped for some reason.

If I replace my UIView animation block with CABasicAnimation it works like a charm.

I was asked to post some animation code:

- (void)shrink {

    if (!self.isStretched) return;

    self.stretched = NO;

    [self hideImageAndLabels];

    [self.indicatorView startAnimating];

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
    animation.duration = duration;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.fromValue = @0;
    animation.toValue = @(shrinkedSize / 2.0);

    [self.layer addAnimation:animation forKey:@"cornerRadiusAnimationRounded"];
    self.layer.cornerRadius = shrinkedSize / 2.0;

    self.heightConstraint.constant = shrinkedSize;
    self.widthConstraint.constant = shrinkedSize;
    self.positionYConstraint.constant = 0;
    self.triangleHeightConstraint.constant = 0;
    self.trianglePositionYConstraint.constant = 14;

    [UIView animateWithDuration:duration * 2 delay:0 usingSpringWithDamping:0.85 initialSpringVelocity:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        [self layoutIfNeeded];
    } completion:^(BOOL finished) {
            //
    }];


}

enter image description here enter image description here

1条回答
一夜七次
2楼-- · 2019-07-24 02:10

I opened a bug on this issue with Google (https://code.google.com/p/gmaps-api-issues/issues/detail?id=10349), and this was their response:

Our understanding is that this is happening because the mapView:willMove: call is being made while already inside a CoreAnimation transaction. Our suggested work around is to wrap the UIView.animateWithDuration call within a dispatch_async back to the main thread. Something along the lines of:

dispatch_async(dispatch_get_main_queue(), ^{ // animation block here. });

Does that help?

Placing the UIView.animateWithDuration block inside a dispatch_async block worked for me.

查看更多
登录 后发表回答