UIPageViewController между двумя UIViewController - PullRequest
0 голосов
/ 26 мая 2018

Я только начал программировать на Swift, и я пытаюсь создать очень простое приложение с начальным значением UIViewController, UIPageViewController, которое показывает несколько страниц книги и место назначения UIViewController.

Мой подход до сих пор таков:

  1. UIViewController1 загружен и имеет кнопку showPage, которая просто показывает UIPageViewController

present(walkthroughViewController, animated: true, completion: nil)

Когда пользователь достигает последней страницы UIPageViewController, я показываю пункт назначения UIViewController2, обращаясь к переходу с самого начала UIViewController

override func onUIPageViewControllerRigthClosing(){
    let pvc = self.presentingViewController as! StartPageController
    dismiss(animated: true){
        pvc.performSegue(withIdentifier: "startTest", sender: nil)
    }
}

Все работает правильно, но проблема в том, что при отклонении UIPageViewController отображается Стартовый UIViewController, а затем отображается второй с анимированным переходом.То, чего я пытаюсь добиться, - это непосредственное отображение цели UiViewController пользователю при отклонении UIPageViewController, без отображения перехода с анимацией от начального вида к конечному виду.

Ясовершенно неправильный подход или есть способ сделать переход перед отклонением UIPageViewController?

Здесь я создал gif, который показывает проблему, когда я закрываю UIPageViewController, я вижу предыдущее представление в переходе: GIF демо

1 Ответ

0 голосов
/ 27 мая 2018

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

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

  • RootViewController (первый экран, пользователь видит после запуска приложения).
  • OnboardingViewController (ваш pageViewController или другой контейнер)
  • AppContentViewController (собственно главный экран приложения)

Я предлагаю вам использовать этот подход: для переходов экрановв RootViewController используйте childViewControllers вместо того, чтобы представлять их модально и отклонять с помощью функций UIKit по умолчанию.

Вот пример кода, который работает с childViewControllers

extension UIViewController {
    func displayChildController(_ content: UIViewController, duration: TimeInterval = 0.4, animation: (() -> ())? = nil, completion: @escaping () -> () = {}) {
        content.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
        view.addSubview(content.view)
        addChildViewController(content)
        UIView.animate(withDuration: animation != nil ? duration : 0, animations: {() -> Void in
            animation?()
        }, completion: {(_ finished: Bool) -> Void in
            content.didMove(toParentViewController: self)
            completion()
        })
    }

    func hideChildController(_ content: UIViewController, duration: TimeInterval = 0.4, animation: (() -> ())? = nil, completion: @escaping () -> () = {}) {

        UIView.animate(withDuration: animation != nil ? duration : 0, animations: {() -> Void in
            animation?()
        }, completion: {(_ finished: Bool) -> Void in
            content.willMove(toParentViewController: nil)
            content.view.removeFromSuperview()
            content.removeFromParentViewController()
            completion()
        })
    }
}

Вот «алгоритм»:

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

  1. Вкл. OnBoardingViewController объявляет onDoneCallback:

    class OnBoardingViewController: ... {
        var onDoneCallback = {}
        ...
    }
    
  2. Вкл. RootViewController при необходимости OnboardingViewController:

    func presentOnboardingScreen() {
        let onboardingVC = self.storyboard?.instantiateViewController(withIdentifier: "OnboardingViewController") as! OnboardingViewController
        onboardingVC.transform = .init(translationX: 0, y: self.view.frame.height)
    
        onboardingVC.onDoneCallback = {
            self.presentAppContentAfterOnboarding() // see below
        }
    
        displayChildController(onboardingVC, duration: 0.3, animation: {
            vc.view.transform = .identity
        })
    }
    
  3. При необходимости вызова onDoneCallback закрытие по OnboardingViewController

  4. presentAppContentAfterOnboarding метод на RootViewController может выглядеть так:

    func presentAppContentAfterOnboarding() {
        let onboardingVC = self.childViewControllers.last as! OnboardingViewController
        let appContentVC = self.storyboard?.instantiateViewController(withIdentifier: "AppContentViewController") as! AppContentViewController
        displayChildController(appContentVC)
        view.insertSubview(appContentVC.view, belowSubview: onboardingVC.view)
        hideChildController(childVC, duration: duration, animation: {
            onboardingVC.view.transform = .init(translationX: 0, y: self.view.frame.height)
        })
    }
    

Примечание.Не забудьте установить ID раскадровки из OnboardingViewController и AppContentViewController в вашей раскадровке.

Вот пример проекта

...