Combining NSLayoutConstraints with CALayer backed

2019-05-04 22:06发布

I have an auto layout setup with an animation that alters a NSLayoutContraint constant value

// set the slide in view's initial height to zero
self.adViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self.adContainerView
                                                           attribute:NSLayoutAttributeHeight
                                                           relatedBy:NSLayoutRelationEqual
                                                              toItem:nil
                                                           attribute:NSLayoutAttributeNotAnAttribute
                                                          multiplier:1.0
                                                            constant:0.0];
[self.view addConstraint:self.adViewHeightConstraint];

//  later, set the slid in view's height to non-zero
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    self.adViewHeightConstraint.constant = 100;
    [UIView animateWithDuration:2.5 animations:^{
        [self.view layoutIfNeeded];
    }];
});

This correctly animated the sizes of the views I have and thus, works correctly. The problem I am seeing, however, is that some custom layer backed views I have are not being redrawn over the duration of the 2.5 sec animation.

The behavior I am seeing is that the custom layer backed views are asked to draw for the final position at the beginning of the animation, then a transform is applied that stretches the view over the duration of the animation until it eventually looks correct.

enter image description here

What these 4 shots show is the red bar animating up, then the two blue views shrinking in height each to accommodate the size reduction. The layer knows how to draw itself correctly for each bounds change, but the animation is not asking it to redraw at each step of the animation... only at the beginning. This is why the black circle looks like an oval — it is the same 2 halves as image #4 but stretched.

The custom CAlayer subclass has one overridden method: drawInContext:, and the layer has needsDisplayOnBoundsChange set to YES.

Thus, the question remains... How can I tell this animation of NSLayoutConstraints to let the views redraw during the entire animation?

1条回答
孤傲高冷的网名
2楼-- · 2019-05-04 22:52

This is a known issue (if you google it you'll see a couple of good hits, though I think this answer, while admittedly focusing of different symptoms, is the most articulate answer I've seen thus far describing the problem UIView scaling during animation ... it's an old answer, but still applicable, I believe).

The easiest solution, IMHO, would be to put the layer in a view that doesn't resize upon animation (e.g. a new view, of fixed size, whose constraints keep it centered on your content view, but doesn't change size as your content view does). That way, you can enjoy the constraints-based animations, but not lose your custom layer's aspect ratio/size.

查看更多
登录 后发表回答