UIPresentationController, анимация обновления selectedContentSize

Итак, у меня есть очень простой UIPresentationController, который в основном отображает contentView по центру экрана, его размер определяется предпочтительным ContentSize контроллера представления. (Он очень похож на обычный контроллер модального представления, представленный в виде FormSheet).

Чего я пытаюсь добиться, так это иметь возможность динамически обновлять размер представления этого контроллера представления, просто изменяя его предпочтительный размер содержимого.

Когда я устанавливаю PreferredContentSize, мой подкласс UIPresentationController получает информацию об этом в:

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

Но как я могу изменить размер кадра просмотра с анимацией? Если я просто позвоню:

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

Сразу вызывается containerViewWillLayoutSubviews и кадр меняется без анимации.

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

Пожалуйста, помогите мне найти способ изменить размер с анимацией. Это должно быть возможно, так как он изменяет размер с анимацией, например, когда происходит вращение.


person DamianD    schedule 27.11.2015    source источник
comment
Вы исправляете это, не используя какой-то странный флаг isAnimating в containerViewWillLayoutSubviews?   -  person fruitcoder    schedule 24.03.2017


Ответы (2)


Вы должны использовать автоматическую раскладку. Сделайте выход из ограничения высоты ваших контейнеров:

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

затем добавьте следующий код:

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

    [UIView animateWithDuration:0.25
                     animations:^{
                       [self.view layoutIfNeeded];
                     }];
}
person Nico S.    schedule 30.05.2016
comment
Хотя это может сработать, нет необходимости использовать автоматическую компоновку, как вы подразумеваете. - person Koen.; 03.07.2020

Вместо того, чтобы устанавливать кадр из preferredContentSizeDidChangeForChildContentContainer, вам нужно только вызвать setNeedsLayout и layoutIfNeeded в представлении контейнера. Это приводит к вызову containerViewWillLayoutSubviews, который обновит кадр, используя вашу конфигурацию анимации.

Цель-C:

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

Свифт:

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()
    })
}

Альтернативный подход

В качестве альтернативы вы могли бы не иметь анимационный блок в preferredContentSizeDidChange..., а вместо этого поместить назначение preferredContentSize в анимационный блок.

Таким образом, у вас будет больше контроля над скоростью анимации отдельных переходов.

Цель-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);
}];

Свифт:

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)
}
person Koen.    schedule 03.07.2020
comment
В представлении контроллера это представляет какую область? - person Blazej SLEBODA; 22.07.2020
comment
Контроллер представления, который вы представляете. Так, например; обновить высоту представленного контроллера представления, когда кто-то прокручивает его. - person Koen.; 22.07.2020