Закрытие ViewController ниже в стеке ведет себя не так, как ожидалось

Я создаю сложное приложение, имеющее ветку посередине.

В какой-то момент в приложении представлен конкретный UIViewController, мы назовем его mainViewController (сокращенно mainVC).

mainVC представляет собой другой контроллер представления по коду, использующему следующий код (я вырезал его части из соображений конфиденциальности):

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"SecondaryStoryboard" bundle:secondaryBundle];
SecondViewController *secondVC = [storyboard instantiateInitialViewController];
[self presentViewController:secondVC animated:YES completion:nil];

Таким образом, secondVC позже представит другой контроллер представления, называемый thirdVC. Это делается с помощью пользовательского перехода, установленного в раскадровке, используемой в приведенном выше коде, который выглядит следующим образом:

@implementation VCCustomPushSegue

- (void)perform {

    UIView *sourceView = ((UIViewController *)self.sourceViewController).view;
    UIView *destinationView = ((UIViewController *)self.destinationViewController).view;

    UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
    destinationView.center = CGPointMake(sourceView.center.x + sourceView.frame.size.width, destinationView.center.y);

    [window insertSubview:destinationView aboveSubview:sourceView];

    [UIView animateWithDuration:0.4
                     animations:^{
                         destinationView.center = CGPointMake(sourceView.center.x, destinationView.center.y);
                         sourceView.center = CGPointMake(0 - sourceView.center.x, destinationView.center.y);
                     }
                     completion:^(BOOL finished){

                         [self.sourceViewController presentViewController:self.destinationViewController animated:NO completion:nil];
                     }];

}

@end

Как вы можете видеть, этот переход модально представляет целевой контроллер представления (с помощью presentViewController:) с пользовательской анимацией (слайд справа налево).

Так что в принципе до сих пор все в порядке. Я представляю secondVC с классической модальной анимацией (слайд вверх снизу) и представляю thirdVC с моим пользовательским переходом.

Но когда я хочу отклонить thirdVC, я хочу вернуться прямо к mainVC. Поэтому я вызываю следующее из thirdVC :

self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:_animate completion:nil];

Таким образом, я вызываю dismissViewControllerAnimated: непосредственно на mainVC (на который ссылается self.presentingViewController.presentingViewController), и я ожидаю, что thirdVC будет отклонено с анимацией, а secondVC просто исчезнет без анимации.

Как Apple говорит в документации по классу UIViewController:

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

Если вы представляете несколько контроллеров представления последовательно, таким образом создавая стек представленных контроллеров представления, вызов этого метода на контроллере представления, расположенном ниже в стеке, отклоняет его непосредственный дочерний контроллер представления и все контроллеры представления выше. этот дочерний элемент в стеке. Когда это происходит, только самый верхний вид удаляется анимированным образом; любые промежуточные контроллеры представления просто удаляются из стека. Самый верхний вид закрывается с использованием его модального стиля перехода, который может отличаться от стилей, используемых другими контроллерами представлений, расположенными ниже в стеке.

Проблема в том, что это не то, что происходит. В моем сценарии thirdVC исчезает и показывает, что secondVC закрывается с классической модальной анимацией слайда вниз.

Что я делаю неправильно ?


Изменить:

Так что ответ @codeFi, вероятно, работает в классическом проекте, но проблема здесь в том, что я работаю над фреймворком. Таким образом, mainVC будет в клиентском приложении, а secondVC и thirdVC в моем фреймворке, в отдельной раскадровке. У меня нет доступа к mainVC каким-либо иным образом, кроме ссылки на него в моем коде, поэтому, к сожалению, здесь нет возможности раскручивать переходы.


person rdurand    schedule 24.09.2014    source источник
comment
Это изменение поведения произошло с iOS 8, в 7 оно работало правильно. Я пытаюсь обойти это сейчас.   -  person theLastNightTrain    schedule 21.10.2014
comment
@theLastNightTrain: ну, вы правы, это происходит только на iOS 8.. Дайте мне знать, если вы найдете что-то на своей стороне..   -  person rdurand    schedule 22.10.2014
comment
@theLastNightTrain: Есть новости? Я был бы рад предложить награду за ответ, решающий эту проблему.   -  person rdurand    schedule 27.10.2014
comment
Извините, нет, в моем случае я обошел это, где это было возможно. Я заметил, что отключение анимации помогает, но это не идеально и означает, что вы не получаете стандартную анимацию.   -  person theLastNightTrain    schedule 27.10.2014


Ответы (2)


У меня была точно такая же проблема, и мне удалось визуально обойти ее, добавив снимок экрана в качестве подпредставления к secondVC.view, например:

if (self.presentedViewController.presentedViewController) {
    [self.presentedViewController.view addSubview:[[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO]];
}

[self dismissViewControllerAnimated:YES completion:nil];

Не красиво, но вроде работает.

ПРИМЕЧАНИЕ. если на вашем secondVC есть панель навигации, вам нужно будет скрыть панель навигации между моментальным снимком экрана и добавлением снимка в качестве подпредставления к secondVC, иначе снимок будет отображаться под панелью навигации. , что, по-видимому, отображает двойную панель навигации во время анимации закрытия. Код:

if (self.presentedViewController.presentedViewController) {
    UIView *snapshot = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
    [self.presentedViewController.navigationController setNavigationBarHidden:YES animated:NO];
    [self.presentedViewController.view addSubview:snapshot];
}

[self dismissViewControllerAnimated:YES completion:nil];
person andersblehr    schedule 10.11.2014
comment
Кажется, работает довольно хорошо .. Все будет хорошо, пока они это не исправят. Спасибо ! - person rdurand; 12.11.2014
comment
Обратите внимание, что если ваш secondVC имеет панель навигации, вам нужно будет скрыть панель навигации между моментальным снимком экрана и добавлением снимка в качестве подпредставления к secondVC, так как в противном случае снимок будет отображаться под панелью навигации, таким образом, отображая двойной панель навигации во время анимации увольнения. - person andersblehr; 12.11.2014
comment
Спасибо за совет, было бы полезно добавить его прямо в ваш ответ. Для меня строка состояния скрыта на обоих ViewController, так что нет проблем :) - person rdurand; 12.11.2014

У меня была такая же проблема, и я исправил ее с помощью UnwindSegues.

По сути, все, что вам нужно сделать, это добавить метод IBAction Unwind Segue в ViewController, к которому вы хотите перейти, а затем подключить в IB действие Exit к вашему методу Unwind Segue.

Пример:

Допустим, у вас есть три ViewController (VC1, VC2, VC3) и вы хотите перейти от VC3 к VC1.

Шаг 1 Добавьте в VC1 метод, подобный следующему:

- (IBAction)unwindToVC1:(UIStoryboardSegue*)sender
{
}

Шаг 2 Перейдите в Interface Builder к VC3 и выберите его. Затем перетащите, удерживая клавишу CTRL, от значка VC к значку Exit и выберите метод, который вы только что добавили в VC1.

Добавить переход на раскрутку

Шаг 3 Находясь в IB и с выбранным VC3, выберите свой Unwind Segue и в инспекторе атрибутов добавьте идентификатор перехода.

введите здесь описание изображениявведите здесь описание изображения

Шаг 4 Перейдите к VC3, где вам нужно выполнить переход (или закрыть VC), и добавьте следующее:

[self performSegueWithIdentifier:@"VC1Segue" sender:self];
person Razvan    schedule 24.09.2014
comment
Привет ! Спасибо за Ваш ответ. В прошлом я использовал раскручивающиеся переходы, но в данном случае это не вариант. Что-то, что я не упомянул, чтобы упростить вопрос, заключается в том, что второй и третий контроллеры представления находятся внутри фреймворка. Таким образом, в основном mainVC находится в клиентском приложении, а два других отделены от него во фреймворке (отсюда и другая раскадровка). Извините, что не сказал этот мой вопрос :) - person rdurand; 24.09.2014