Неправильная рамка при отклонении модально представленного контроллера представления

Я представляю UIViewController с использованием настраиваемого перехода и пользовательского UIPresentationController. Вид контроллера просмотра не охватывает весь экран, поэтому контроллер представления представления все еще отображается.

Затем я представляю экземпляр UIImagePickerController поверх этого контроллера представления. Проблема в том, что когда я увольняю сборщик изображений, рамка контроллера представления выглядит как весь участок, который я хочу, чтобы покрыть весь экран. Кадр, указанный frameOfPresentedViewInContainerView в моем пользовательском UIPresentationController, кажется, полностью игнорируется.

Только если присутствует сборщик изображений с modalPresentationStyle of UIModalPresentationOverCurrentContext, мои кадры остаются неповрежденными (что имеет смысл, поскольку вначале не видны представления из иерархии представлений). К сожалению, это не то, что я хочу. Я хочу, чтобы сборщик изображений отображался в полноэкранном режиме, который - по какой-то причине - кажется, испортил мой макет. Что-нибудь, что я могу сделать неправильно или забыть здесь? Любые предложения?

Ответ 1

Я попробовал оба упомянутых подхода к оболочке. Один из побочных эффектов использования этого метода обертывания заключается в том, что вращение устройства не проявляется хорошо - введение черных ящиков вокруг представленного представления.

Вместо того, чтобы делать обертку, попробуйте установить modalPresentationStyle представленного UIImagePickerController на UIModalPresentationOverFullScreen. Это означает, что представления под элементом выбора изображений не будут удалены/восстановлены из иерархии представлений во время презентации/увольнения.

Ответ 2

Это ожидается, потому что полноэкранная презентация не восстанавливает исходный кадр, рассчитанный frameOfPresentedViewInContainerView. Рекомендуемый способ исправить это - создать представление оболочки, в которое вы будете вставлять представленное представление контроллера представления. Вот соответствующий код для вашего пользовательского контроллера представления:

- (void)presentationTransitionWillBegin {
    // wrapper is a property defined in the custom presentation controller.
    self.wrapper = [UIView new];
    [self.wrapper addSubview:self.presentedViewController.view];
}

- (CGRect)frameOfPresentedViewInContainerView {
    CGRect result = self.containerView.frame;

    // In this example we are doing a half-modal presentation
    CGFloat height = result.size.height/2;
    result.origin.y = height;
    result.size.height = height;

    return result;
}

- (UIView *)presentedView {
    return self.wrapper;
}

- (BOOL)shouldPresentInFullscreen {
    return NO;
}

- (void)containerViewWillLayoutSubviews {
    self.wrapper.frame = self.containerView.frame;
    self.presentedViewController.view.frame = [self frameOfPresentedViewInContainerView];
}

Обратите внимание, что мы переопределяем presentedView, чтобы вернуть представление оболочки вместо значения по умолчанию - представленное представление контроллера представления. Таким образом, даже если второе представление изменяет рамку обертки, представленный вид контроллера представления не изменится.

Ответ 3

решение erudel не работало для меня, как есть, но добавление другого представления между wrapperView и presentedViewController.view было трюком (я понятия не имею, почему ):

- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController
                       presentingViewController:(UIViewController *)presentingViewController {
    if (self = [super initWithPresentedViewController:presentedViewController
                             presentingViewController:presentingViewController]) {
        _wrapperView = [[UIView alloc] init];
        _wrapperView2 = [[UIView alloc] init]; // <- new view
    }
    return self;
}

- (CGRect)frameOfPresentedViewInContainerView {
    return self.containerView.bounds;
}

- (UIView *)presentedView {
    return self.wrapperView;
}

- (BOOL)shouldPresentInFullscreen {
    return NO;
}

- (void)containerViewWillLayoutSubviews {
    self.wrapperView.frame = self.containerView.frame;
    self.wrapperView2.frame = /* your custom frame goes here */;
    self.presentedViewController.view.frame = self.wrapperView2.bounds;
}

- (void)presentationTransitionWillBegin {
    [self.wrapperView addSubview:self.wrapperView2];
    [self.wrapperView2 addSubview:self.presentedViewController.view];

    // Set up a dimming view, etc
}

Протестировано на iOS 9.3.

Ответ 4

Это сработало для меня, в UIPresentationController:

override func containerViewWillLayoutSubviews() {

     super.containerViewWillLayoutSubviews()
     presentedViewController.view.frame = frameOfPresentedViewInContainerView
}

Ответ 5

Я пробовал containerViewWillLayoutSubviews, но он не работал. Я хотел бы избежать дополнительных оберток, если это возможно. Я придумал эту стратегию исправления кадра на представлении с помощью presentedView. Кроме того, мне удалось удалить containerViewWillLayoutSubviews. forceFrame настраивается на наш конкретный вариант использования. presentedFrame устанавливается нашим пользовательским аниматором.

class CustomModalPresentationController: UIPresentationController {

        var presentedFrame = CGRect.zero
        var forceFrame = false

        override func dismissalTransitionWillBegin() {
            forceFrame = false
        }
        override func presentationTransitionDidEnd(_ completed: Bool) {
            forceFrame = true
        }
        override var presentedView: UIView? {
            if forceFrame {
                presentedViewController.view.frame = presentedFrame
            }
            return presentedViewController.view
        }
        override var frameOfPresentedViewInContainerView: CGRect {
            return presentedFrame
        }
    }