Развернуть Segue, не закрывая View Controller с помощью UIModalPresentationCustom

Я представляю контроллер модального представления, используя пользовательский переход (устанавливая его modelPresentationStyle в UIModalPresentationCustom, предоставляя переходный делегат и UIViewControllerAnimatedTransitioning объект).

В представленном контроллере представления у меня есть переход на раскрутку, подключенный к кнопке. Переход срабатывает просто отлично; вызывается метод IBAction в представленном контроллере представления, а также prepareForSegue в представленном контроллере представления. Однако представленный контроллер представления не отклоняется, и соответствующий метод делегата перехода (animationControllerForDismissedController:) не вызывается.

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

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

Я знаю, что я мог бы вызвать dismissViewControllerAnimated:completion: в методе IBAction контроллера представления представления, но я бы предпочел использовать это как последнее средство и заставить раскручивать переход, работающий так, как должен (или, по крайней мере, знать, почему он не работает :) ).

Любая помощь приветствуется,

заранее спасибо


person baxterma    schedule 25.02.2015    source источник
comment
У меня такая же проблема, вы когда-нибудь решали ее, не прибегая к rejectViewControllerAnimated:completion ?   -  person Chris    schedule 23.04.2015
comment
Эй, Крис, я решил это, но, честно говоря, я не могу вспомнить, как. Как вы, наверное, заметили, я разместил этот вопрос несколько месяцев назад, и с тех пор мы удалили переход. Кажется, я помню, как переопределял adaptivePresentationStyle в PresentationController и возвращал UIModalPresentationOverFullScreen. Я думаю, что это имеет тот же эффект, что и установка modalPresentationStyle в VC, но по-прежнему разрешает пользовательский переход. Извините, я не могу больше помочь.   -  person baxterma    schedule 23.04.2015
comment
Имейте точно такую ​​же проблему. Все хорошо с настоящим переходом и пользовательским настоящим переходом. Но раскрутить переход полностью не удается. Не отклоняет, не говоря уже о применении пользовательского перехода отклонения. Так же, как и вы, я могу заменить переход на раскрутку с помощью DisnViewControllerAnimated. Это решает проблему. Однако это не идеально, так как я бы предпочел постоянно использовать переходы повсюду.   -  person Max MacLeod    schedule 28.04.2015
comment
Похоже, та же проблема stackoverflow.com/questions/25654941/   -  person Max MacLeod    schedule 28.04.2015


Ответы (2)


Кажется, что если вы используете UIModalPresentationCustom для представления контроллера с помощью пользовательского менеджера переходов, вам также нужно использовать собственный менеджер переходов, чтобы отклонить его (что, я думаю, имеет смысл, поскольку вы можете делать всевозможные странные вещи в объекте аниматора и UIKit не может быть уверен, что простое закрытие экрана, как обычно, полностью восстановит исходное состояние - я просто хочу, чтобы он сказал вам это явно...).

Вот что я сделал, чтобы исправить это в своем приложении:

  • переопределить segueForUnwindingToViewController в родительском контроллере представления (тот, к которому вы переходите после анимации отклонения) и вернуть экземпляр вашего UIStoryboardSegue, либо тот, который вы использовали для исходного перехода, либо новый отдельный класс
  • если целевой контроллер представления unwind segue находится в навигационной иерархии, вам необходимо вместо этого переопределить этот метод в навигационном контроллере
  • в вызове метода perform dismissViewControllerAnimated
  • представленный контроллер представления должен по-прежнему содержать действительную ссылку на переходный делегат, иначе вы получите EXC_BAD_ACCESS (см. DismissViewControllerAnimated EXC_Bad_ACCESS при true) - так что либо сделайте так, чтобы делегат оставался строгой ссылкой, как описано в этом потоке, либо назначьте новый перед вызовом dismissViewControllerAnimated (возможно, изменение modelPresentationStyle, например, на полноэкранный режим перед отклонением, тоже сработает, но я не пробовал это)
  • если анимация отклонения должна делать какие-либо нестандартные вещи (моя, к счастью, этого не сделала), переопределите animationControllerForDismissedController в объекте диспетчера переходов и верните правильный аниматор
  • если целевой контроллер представления находится в навигационной иерархии, вам также необходимо вручную поместить стек навигации в целевой контроллер, прежде чем закрыть представленный экран (т.е. target.navigationController!.popToViewController(target, animated: false))

Полный пример кода:

// custom navigation controller 

override func segueForUnwindingToViewController(toViewController: UIViewController,
fromViewController: UIViewController,
identifier: String?) -> UIStoryboardSegue {
    return CustomSegue(
        identifier: identifier,
        source: fromViewController,
        destination: toViewController
    )
}


// presented VC

var customTransitionManager: UIViewControllerTransitioningDelegate?


// custom segue

override func perform() {
    let source = sourceViewController as! UIViewController

    if let target = destinationViewController as? PresentedViewController {
        let transitionManager = TransitionManager()
        target.modalPresentationStyle = .Custom
        target.customTransitionManager = transitionManager
        target.transitioningDelegate = transitionManager

        source.presentViewController(target, animated: true, completion: nil)
    } else if let target = destinationViewController as? WelcomeViewController {
        target.navigationController!.popToViewController(target, animated: false)
        target.dismissViewControllerAnimated(true, completion: nil)
    } else {
        NSLog("Error: segue executed with unexpected view controllers")
    }
}
person Kuba Suder    schedule 21.07.2015

Я также столкнулся с этой проблемой, когда мне нужно передать данные обратно из модального представления. Я бродил по Google и здесь пару часов, но не смог найти ответ, понятный для меня. Но я получил некоторый намек, и вот обходной путь. Кажется, что это связано с тем, что он должен передавать данные обратно, а процесс отклонения от автоматического раскручивания предшествует передаче данных, которая предотвратила отклонение ViewController. Поэтому я думаю, что мне нужно вручную отклонить его еще раз.

Мне тут повезло. Я не заметил, что это был дочерний контроллер просмотра. Я только что настроил его из раскадровки.

А затем в функции Unwind я добавил строки, чтобы удалить дочерний контроллер представления и дочернее представление. У меня нет кода в sourceViewController.

Свифт 4.1

@IBAction func unwindToVC(sender :UIStoryboardSegue){

    if let source = sender.source as? CoreLocationVC{
        if source.pinnedCity != nil{
             clCity = source.pinnedCity
        }
        if source.pinnedCountry != nil {
            clCountry = source.pinnedCountry
        }
        if source.pinnedTimeZone != nil {
            clTimeZone = source.pinnedTimeZone
        }
        if source.pinnedLocation != nil {
            clLocation = source.pinnedLocation
        }
        // I added 2 lines here and it just worked
        source.view.removeFromSuperview()
        source.removeFromParentViewController()


    }
person William Tong    schedule 26.08.2018