Pregunta

I have a view controller which adds a UIPageViewController to a subview (let's call it "overlay") programmatically. Since the page view controller's pages each have a different height, I added an NSLayoutConstraint on the "overlay" subview.

On every swipe I calculate the height of the upcoming view controller and resize the overlay view accordingly:

- (void)resizeOverlayToBottomOf:(UIView *)element {

   // resize overlay in parent view controller so it shows the element
   float bottomOfElement = element.frame.origin.y + element.frame.size.height + 20;
   [self.parentViewController.overlayHeightConstraint setConstant:bottomOfElement];

   [self.parentViewController.overlayView setNeedsUpdateConstraints];
   [self.parentViewController.overlayView setNeedsLayout];
   [self.parentViewController.overlayView layoutIfNeeded];
}

Everything works as expected... until I want to change the overlay size with an animation.
I wrapped the last two lines of the above method with an animation block:

[UIView animateWithDuration:0.25f animations:^{
   [self.parentViewController.overlayView setNeedsLayout];
   [self.parentViewController.overlayView layoutIfNeeded];
}];

Now after a swipe completes, the height of the overlay view changes with an animation.

The Problem is that while the animation plays, the page view controller's content snaps back to some place off screen and swipes back in. I tried adding constraints to ensure a fixed width of the page view controller content, but nothing seems to do the trick.

Any hint on how to animate the parent view without affecting the page view controller views will be highly appreciated!

¿Fue útil?

Solución 2

Well, this bit of code did the trick:

[UIView animateWithDuration:0.25f animations:^{
    // [self.parentViewController.overlayView setNeedsLayout];
    // [self.parentViewController.overlayView layoutIfNeeded];
    CGRect frame = self.parentViewController.overlayView.frame;
    frame.size.height = bottomOfElement;
    self.parentViewController.overlayView.frame = frame;
}];

The funny thing is, it does not seem to matter what value I use for frame.size.height, the constraint seems to be put in currently anyway.

If someone could explain why this works, I'd be delighted.

Otros consejos

I recently had the same problem. This apparently works:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
    if (completed)
    {
        CGFloat height = [self calculateHeight];
        [CATransaction begin];
        [CATransaction setCompletionBlock:^{
            self.heightConstraint.constant = height;
            [UIView animateWithDuration: 0.25
                                  delay: 0
                                options: UIViewAnimationOptionCurveEaseInOut
                             animations:^{

                                 [self.view layoutIfNeeded];
                             }
                             completion:^(BOOL finished) {

                             }];
        }];
        [CATransaction commit];
    }
}

My understanding is that one animation interferes with the other.
CATransaction intercepts the current animation and will do it's completion block after the current animation is done.
This works fine for me.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top