Reputation: 703
I learn the book iOS Animations by Tutorials
But I don't use Storyboard. I have several ViewControllers created programmatically. I have added RootVC in AppDelegate.swift. This application is working without navigation to the RootVC (going to the beginning) and the screens looks like that:
My question is about how to create such a navigation between different screens (ViewControllers) in Swift 4 (Xcode 10.2.1). It looks like there is an issue with looping... when the last ViewController instantiates the first RootVC and so on...
At the end I would like to have different custom navigation transitions on one ViewController (with .present() and with .navigationController?.pushViewController()
import UIKit
class FadePresentAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let duration = 1.0
var presenting = true
var originFrame = CGRect.zero
var dismissCompletion: (()->Void)?
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
//Setting the transition’s context
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
//Adding a fade transition
let containerView = transitionContext.containerView
let toView = transitionContext.view(forKey: .to)!
containerView.addSubview(toView)
toView.alpha = 0.0
UIView.animate(withDuration: duration,
animations: {
toView.alpha = 1.0
},
completion: { _ in
transitionContext.completeTransition(true)
}
)
}
}
import UIKit
//UIViewControllerTransitioningDelegate for self.present(self.nextScreen, animated: true, completion: nil)
//UINavigationControllerDelegate for self.navigationController?.pushViewController(self.nextScreen, animated: true)
class Screen3: UIViewController, UIViewControllerTransitioningDelegate, UINavigationControllerDelegate {
let nextScreen = RootVC() //4th Screen //<----- EXEC ERRROR
let transition = FadePresentAnimator()
let btnSize:CGFloat = 56.0
let btn1 = ClickableButton()
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Screen 3"
view.backgroundColor = HexColor.Named.BabyBlue
self.navigationController?.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupLayout()
}
private func setupLayout() {
//btn1:
view.addSubview(btn1)
btn1.setDefaultTitle(title: "▶") // ⏹ "▶" "■"
btn1.apply(height: btnSize)
btn1.apply(width: btnSize)
btn1.applyDefaultStyle()
if #available(iOS 11.0, *) {
btn1.alignXCenter(to: view.safeAreaLayoutGuide.centerXAnchor)
} else {
// Fallback on earlier versions
}
if #available(iOS 11.0, *) {
btn1.alignYCenter(to: view.safeAreaLayoutGuide.centerYAnchor)
} else {
// Fallback on earlier versions
}
btn1.clickHandler {
self.nextScreen.transitioningDelegate = self
//self.present(self.nextScreen, animated: true, completion: nil)
self.navigationController?.pushViewController(self.nextScreen, animated: true)
}
}
//forward
func animationController(forPresented presented: UIViewController,
presenting: UIViewController, source: UIViewController) ->
UIViewControllerAnimatedTransitioning? {
return transition
}
//backward
func animationController(forDismissed dismissed: UIViewController) ->
UIViewControllerAnimatedTransitioning? {
return nil
}
}
//
// AppDelegate.swift
// Anime-Control-01
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//No Storyboards!
window = UIWindow(frame:UIScreen.main.bounds)
window?.makeKeyAndVisible()
let rootVC = RootVC() //RootVC.swift
let rootController = UINavigationController(rootViewController: rootVC)
window?.rootViewController = rootController
return true
}
}
Upvotes: 0
Views: 736
Reputation: 58
It looks like there is an issue with looping... when the last ViewController instantiates the first RootVC and so on...
Yeah, you're totally right. The thing is you're creating next ViewController right when current ViewController is initialized.
nextScreen
initialized lazily "on demand" by replacing this linelet nextScreen = RootVC()
by this one lazy var nextScreen = RootVC()
Or to create nextScreen
variable right before the transition:
btn1.clickHandler {
let nextScreen = RootVC()
nextScreen.transitioningDelegate = self
navigationController?.pushViewController(nextScreen, animated: true)
}
Upvotes: 1