我刚刚开始使用Swift进行编程,我想要完成的是一个非常简单的应用程序,其初始版本为UIViewController
,UIPageViewController
显示了一些书页和一个目的地UIViewController
。
到目前为止,我的方法是:
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
,然后显示动画segue的第二个。
我想要实现的是在解除UiViewController
时直接向用户显示目标UIPageViewController
,而不显示从开始视图到目标视图的动画转换。
在接近UIPageViewController
之前,我是否完全错误接近或有办法解决这个问题?
在这里,我创建了一个显示问题的gif,当我关闭UIPageViewController
时,我看到转换中的上一个视图:GIF demo
答案 0 :(得分:0)
我建议你使用这种方法:对于这些屏幕,转换使用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()
})
}
}
这是“算法”:
我假设您正在使用包含所有这些视图控制器的单个故事板。
在OnBoardingViewController
声明onDoneCallback
:
class OnBoardingViewController: ... {
var onDoneCallback = {}
...
}
当您需要出席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
})
}
当您需要在onDoneCallback
OnboardingViewController
时关闭
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)
})
}
请注意。不要忘记在故事板中设置OnboardingViewController
和AppContentViewController
的 Storyboard ID 。