Отклонить и представить контроллер модального вида с одной анимацией


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

Моя структура раскадровки:

Введите описание изображения здесь Можно сказать, что A контроллер-это то, что следует за NavigationController, B - это ссылка на запуск, а C - это ViewController панели вкладок. И B , и C представлены модально с переходом Cross Dissolve.

Когда пользователь входит в приложение (из B), контроллер C представлен модально с флип-горизонтальным переходом. И когда пользователь выходит из системы (из C), B представляется таким же образом. НаA контроллере я выполняю прямой переход кB илиC в зависимости от того, зарегистрирован пользователь или нет.

Моя проблема заключается в том, что если я не уволю предыдущий контроллер вида из B или C, этот контроллер просочится. Напротив, если я отклоняю его, A является показано перед целевым контроллером (B или C ).

Можно ли показать только перевернутый горизонтальный переход и перешагнуть черезвид ?

3   5   2017-01-24 15:13:29

3 ответа:

Моим решением этой проблемы была замена текущего rootViewController, поддерживающего различные переходы:

static func replaceRootViewController(with: UIViewController, transition: UIViewAnimationOptions, completion: (() -> ())? = nil) {        
    if transition == .transitionCrossDissolve {
        let overlayView = UIScreen.main.snapshotView(afterScreenUpdates: false)
        with.view.addSubview(overlayView)
        UIApplication.shared.keyWindow?.rootViewController = with

        UIView.animate(withDuration: 0.65, delay: 0, options: transition, animations: {
            overlayView.alpha = 0
        }, completion: { finished in
            overlayView.removeFromSuperview()
            if let completion = completion{
                completion()
            }
        })
    } else {
        _ = with.view
        UIView.transition(with: UIApplication.shared.keyWindow!, duration: 0.65,options: transition, animations: {
            UIApplication.shared.keyWindow?.rootViewController = with
        }){_ in
            if let completion = completion {
                completion()
            }

        }
    }
}

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

Добавил Этот метод в категорию к UIViewController, после чего может вызвать любое ранее вызванное presentViewController:animated:completion. Результатом является плавная анимация нового контроллера, в то же время игнорируя предыдущий.

-(void)presentViewControllerDismissingPrevious:(UIViewController* _Nonnull)controller animated:(BOOL)animated completion:(void (^ __nullable)(void))completion {

    UIViewController* visibleController = self;
    {
        UIViewController* temp;
        while( ( temp = visibleController.presentedViewController ) != nil ) {
            visibleController = temp;
        }
    }

    if( visibleController == self ) {
        // no previous controller to dismiss
        [self presentViewController:controller animated:animated completion:completion];
    } else {
        // create a temporary snapshot of the visible controller's entire window
        // and add to the current view controller's window until animation completed
        UIWindow* visibleWindow = visibleController.view.window;
        UIView* tempView = [visibleWindow snapshotViewAfterScreenUpdates:NO];
        UIView* rootView = self.view.window.subviews[0];
        tempView.frame = [rootView convertRect:visibleWindow.bounds fromView:visibleWindow];
        [rootView addSubview:tempView];

        [self dismissViewControllerAnimated:NO completion:^(){
            [self presentViewController:controller animated:animated completion:^(){
                [tempView removeFromSuperview];
                if( completion ) {
                    completion();
                }
            }];
        }];
    }
}

Оба ответа были очень полезны, вот версияSwift 4 :

func presentHidingBehindScreenSnapshot(viewController: UIViewController,
                                     completion: (() -> (Void))? ) {
if let screenSnapshot = UIApplication.shared.keyWindow?.snapshotView(afterScreenUpdates: false),
  let rootViewController = UIApplication.shared.keyWindow?.rootViewController {
  rootViewController.view.addSubview(screenSnapshot)
  rootViewController.view.bringSubview(toFront: screenSnapshot)

  rootViewController.dismiss(animated: false, completion: {
    rootViewController.present(viewController, animated: false, completion: {
      screenSnapshot.removeFromSuperview()
      if let existingCompletion = completion {
        existingCompletion()
      }
    })
  })
} else {
  #if DEBUG
  fatalError("Can't hide behind snapshot while presenting other view controller")
  #endif
}

}