Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIPresentationController preferredContentSize update animated

So I have a very basic UIPresentationController that basically display contentView centered on screen, it's size is determined by view controller preferredContentSize. (Its very much similar to regular modal view controller presented as FormSheet).

What I'm trying to achieve, is to be able to update size of this view controllers' view dynamically, by just changing it's preferredContentSize.

When I set preferredContentSize, my subclass of UIPresentationController receive information about it in:

-(void)preferredContentSizeDidChangeForChildContentContainer:(id<UIContentContainer>)container

But how can I from here resize the view frame with animation ? If I just call:

-(void)preferredContentSizeDidChangeForChildContentContainer:(id<UIContentContainer>)container
{
    [UIView animateWithDuration:1.0 animations:^{
        self.presentedView.frame = [self frameOfPresentedViewInContainerView];
    } completion:nil]; 
}

Immediately gets called containerViewWillLayoutSubviews and frame is changed without animation.

-(void)containerViewWillLayoutSubviews
{
    self.presentedView.frame = [self frameOfPresentedViewInContainerView];
}

Please help me find a way, to resize it with animation. It must be possible, since it resizes with animation for example when rotation happens.

like image 442
DamianD Avatar asked Oct 31 '22 14:10

DamianD


2 Answers

Instead of setting the frame from within preferredContentSizeDidChangeForChildContentContainer, you only need to call setNeedsLayout and layoutIfNeeded on the container view. This causes containerViewWillLayoutSubviews to be invoked, which will update the frame using your animation configuration.

Objective-C:

- (void)preferredContentSizeDidChangeForChildContentContainer:(id<UIContentContainer>)container
{
    [UIView animateWithDuration:1.0 animations:^{
        [self.containerView setNeedsLayout];
        [self.containerView layoutIfNeeded];
    } completion:nil]; 
}

Swift:

override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
    super.preferredContentSizeDidChange(forChildContentContainer: container)
    
    guard let containerView = containerView else {
        return
    }
    
    UIView.animate(withDuration: 1.0, animations: {
        containerView.setNeedsLayout()
        containerView.layoutIfNeeded()
    })
}

Alternative approach

Alternatively you could not have the animate block in preferredContentSizeDidChange..., and instead place the assignment of preferredContentSize in an animate block.

This way you have more control over the animation speed of individual transitions.

Objective-C:

- (void)preferredContentSizeDidChangeForChildContentContainer:(id<UIContentContainer>)container
{
    [self.containerView setNeedsLayout];
    [self.containerView layoutIfNeeded];
}

// In view controller:

[UIView animateWithDuration:0.25 animations:^{
    self.preferredContentSize = CGSizeMake(self.view.bounds.width, 500.f);
}];

Swift:

override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
    super.preferredContentSizeDidChange(forChildContentContainer: container)
    
    guard let containerView = containerView else {
        return
    }
    
    containerView.setNeedsLayout()
    containerView.layoutIfNeeded()
}

// In view controller

UIView.animate(withDuration: 0.25) {
    self.preferredContentSize = CGSize(width: self.view.width, height: 500)
}
like image 62
Koen. Avatar answered Nov 15 '22 06:11

Koen.


You have to use auto layout. Make an outlet from your containers height constraint:

@property (nonatomic, strong, readwrite) IBOutlet NSLayoutConstraint *drawerViewHeightConstraint;

then add the following code:

- (void)preferredContentSizeDidChangeForChildContentContainer:(id<UIContentContainer>)container
{
    [super preferredContentSizeDidChangeForChildContentContainer:container];
    self.drawerViewHeightConstraint.constant = container.preferredContentSize.height;

    [UIView animateWithDuration:0.25
                     animations:^{
                       [self.view layoutIfNeeded];
                     }];
}
like image 25
Nico S. Avatar answered Nov 15 '22 07:11

Nico S.