Scene Transition not working anymore after having change ViewController - ios

Here is the way I navigate between different ViewControllers:
let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController3")
UIApplication.topViewController()?.present(newViewController, animated: true, completion: nil)
with the following extension:
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
And here is the way I invoke scene transitions in my SKScene (several):
let transition = SKTransition.fade(withDuration: 2)
let nextScene = NewScene(size: scene!.size)
nextScene.scaleMode = .aspectFill
scene?.view?.presentScene(nextScene, transition: transition)
Everything work fine before switching ViewControllers. Once the switching has been succeeded, I can not invoke transition anymore in my SKScene, the app get frozen without any error from Xcode (iPad connected to the Mac with live debugging)
Do you know what happens ?
I use Swift 3 and SpriteKit with ViewControllers to be able to use Vuforia static lib in a direct ViewController scene (UIView).

I have finally found the solution, it's necessary to dismiss the actual ViewController before changing with the new one:
self.dismiss(animated: false)
let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "viewController2")
UIApplication.topViewController()?.present(newViewController, animated: true, completion: nil)
If the dismiss call is not done, it's not possible to do new transition scene in the new ViewController.

Related

Navigation Bar disappears when going back to Home VC from a Details VC from Push Notification

If I click on the push notification, it takes me to the details page but when I click on the programatically created back button, it takes me back to HomeVC but with the top nav bar gone. Here is my app delegate function where I present the details VC :
private func gotoDetailsVC(value : String)
{
guard let window = UIApplication.shared.connectedScenes.filter({$0.activationState == .foregroundActive
|| $0.activationState == .background || $0.activationState == .foregroundInactive}).compactMap({$0 as? UIWindowScene}).first?.windows.filter({$0.isKeyWindow}).first
else { return }
let storyboard = UIStoryboard(name: "Home", bundle: nil)
let detailsVC = storyboard.instantiateViewController(identifier: "viewDeviceDataController") as viewDeviceDataController
detailsVC.deviceID = value
detailsVC.didComeFromPN = true
let navController = UINavigationController(rootViewController: detailsVC)
navController.modalPresentationStyle = .popover
// you can assign your vc directly or push it in navigation stack as follows:
window.rootViewController = navController
window.makeKeyAndVisible()
}
And here is my back button on the DetailsVC :
#objc func backAction() {
let storyboard = UIStoryboard.init(name: "Home", bundle: nil)
let homeVC = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
homeVC.modalPresentationStyle = .automatic
present(homeVC, animated: true, completion: nil)
}
How can I resolve this issue? Please help.
Resolved by navigating to root Navigation Controller.
#objc func backAction() {
let storyboard = UIStoryboard.init(name: "Home", bundle: nil)
let homeVC = storyboard.instantiateViewController(withIdentifier: "navControllerHome") as! UINavigationController
homeVC.modalPresentationStyle = .fullScreen
present(homeVC, animated: true, completion: nil)
}
Usually back action would just return to a previous state, but here it seems you are recreating the view.
I would not make private func gotoDetailsVC(value : String) replace rootViewController and instead make it be presented by current navigationController then on your back action you would not create a new home but dismiss your detail screen.

Back to root view controller in swift

Is there any way to dismiss all the view controllers ( in which some controllers are pushed through navigation) and go back to the root view controller. I saw lots of examples but they didn't work in my application. I am using swift 4
This is code in appdelegate
func setNavigationToRootViews(){
storyBoard = UIStoryboard(name: "Main", bundle: nil)
nav = storyBoard?.instantiateViewController(withIdentifier: "mainNavigation") as! UINavigationController?
let accessToken: String? = KeychainWrapper.standard.string(forKey: "token")
print(accessToken as Any)
if accessToken != nil {
let homeVc = storyBoard?.instantiateViewController(withIdentifier: "Home-VC") as! HomeViewController
nav?.pushViewController(homeVc, animated: false)
}else{
let welcomVc = storyBoard?.instantiateViewController(withIdentifier: "login-VC") as! LoginViewController
nav?.pushViewController(welcomVc, animated: false)
}
let leftMenuVC = storyBoard?.instantiateViewController(withIdentifier: "menu-VC") as! MenuViewController
container = MFSideMenuContainerViewController.container(withCenter: nav, leftMenuViewController: leftMenuVC, rightMenuViewController: nil)
container?.panMode = MFSideMenuPanModeNone
window?.rootViewController = container
window?.makeKeyAndVisible()
}
and this in my last View controller
#IBAction func okayBtnTapped(_ sender: Any) {
_ = self.navigationController?.popToRootViewController(animated:
true)
dismiss(animated: true, completion: nil)
}
Try this one:
self.navigationController?.popToRootViewController(animated: true)
You can just set a new RootController like this:
let storyboard = UIStoryboard(name: "sName", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "<YOUR ROOT CONTROLLER>")
self.window?.rootViewController = viewController
If you don't have a window at self.window you need to instanciate one based on your AppDelegate.
If you're within a NavigationController you can also use the answer of #Anshul Bhatheja
Check you navigation controller, and view controllers inside that navigation controller. It seems debugging issue.
this method popToRootViewController(animated:) is the method should work
If you are working with simple push navigation controller and you want to go back to root view controller then you simply have to write
_ = self.navigationController?.popToRootViewController(animated: true)
extension UINavigationController {
func popToViewController(ofClass: AnyClass, animated: Bool = true) {
if let vc = viewControllers.filter({$0.isKind(of: ofClass)}).last {
popToViewController(vc, animated: animated)
}
}
func popViewControllers(viewsToPop: Int, animated: Bool = true) {
if viewControllers.count > viewsToPop {
let vc = viewControllers[viewControllers.count - viewsToPop - 1]
popToViewController(vc, animated: animated)
}
}
}
pop to SomeViewController class
navigationController?.popToViewController(ofClass: SomeViewController.self)
pop 2 view controllers
navigationController?.popViewControllers(viewsToPop: 2)

How can I show ViewController in UITabBarController?

I have a UITabBarController and all my other view controllers are connected to it. Now I want to show one my controller as:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: ViewController = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
but when I tried to:
let rootViewController = self.window?.rootViewController as! UINavigationController
rootViewController.pushViewController(vc, animated: true)
it gave me the next error:
Could not cast value of type 'UITabBarController' (0x1a899b818) to 'UINavigationController'
Later I've tried to do:
let rootViewController = self.window?.rootViewController as! UITabBarController
but in this case I get
UITabBar has no member pushViewController
How can I show/push my ViewController so it will appear with UINavigationBar and inside of UITabBar?
You need to place each of your view controllers inside a navigation controller.
E.g. currently you have a TabBarViewController
and two view controllers:
ViewControllerA
ViewControllerB
What you need to do is to embed each of them inside a navigation controller so you would have:
UINavigationController -> ViewControllerA
UINavigationController -> ViewControllerB
In order to push a new controller you would do:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: ViewController = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
let navViewController = myTabBar.selectedViewController as? UINavigationController
navViewController?.pushViewController(vc, animated: true)
Could not cast value of type 'UITabBarController' (0x1a899b818) to 'UINavigationController'
Your root view controller is of type UITabBarController.
Therefore you have to use the appropriate methods of this class and not UINavigationController.
To set view controllers use either
var viewControllers: [UIViewController]? or
func setViewControllers([UIViewController]?, animated: Bool).
To have a navigation bar you have to instantiate a UINavigationController and add your view controller to this navigation controller.
Then add your navigation controller to your UITabBarController with via one of the above options.
If your class is UITabBarController
You can add this:
private func showViewController() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "queueTableViewController") as? QueueTableViewController else { return }
let navVC = self.selectedViewController as? UINavigationController
navVC?.pushViewController(vc, animated: true)
}
This will allow you to go to any VC
The second solution is something like this.
Here You will show the last VC and from there push some VC.
guard let tabCount = viewControllers?.count, tabCount > 1 else { return }
selectedIndex = tabCount - 1
if let navigationController = viewControllers?[selectedIndex] as? UINavigationController {
if let accountVC = navigationController.visibleViewController as? FirstViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "someViewController") as? SomeViewController else { return }
accountVC.navigationController?.pushViewController(vc, animated: true)
}
}

Swift / How to set (and load) a new root view controller

I have a RootVC. It is a SwipeViewController: UINavigationController.
SwipeViewController
Within WelcomeNavigationController, I'm checking a condition. If that condition is true, I want to open the RootVC.
class WelcomeNavigationController: UINavigationController {
override func viewWillAppear(animated: Bool) {
backendless.userService.setStayLoggedIn(true)
if backendless.userService.currentUser != nil {
print("currentUser != nil")
dispatch_async(dispatch_get_main_queue()) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc : RootVC = storyboard.instantiateViewControllerWithIdentifier("RootVC") as! RootVC
appDelegate.window?.rootViewController = vc
appDelegate.window?.makeKeyAndVisible()
}
}
}
The print statement is executed and some print statements from my RootVC are executed as well. So in theory the RootVC is loaded. But it is not visible. How can I make my RootVC visible?
Help is very appreciated.
I think you should be add rootVC to current view controller
self.addChildViewController(vc)
vc.view.frame = self.view.frame
self.view.addSubview(vc.view)
vc.didMoveToParentViewController(self)

SpriteKit: Black Screen after move from SKScene to UIViewController

I'm stuck on transitioning from an SKScene to a ViewController that I've added to the Main.storyboard. I know there are tons of the same question but nothing works for me.
I would be grateful if I get an answer, anyway.
My code to transition:
func presentNextVC() {
let vc = UIViewController(nibName: "NextVC", bundle: nil) as UIViewController
if let responder = self.view?.nextResponder() {
let vc = responder as UIViewController
vc.presentViewController(NextVC(), animated:true, completion:nil)
}
This function will be called by a TouchedNode-event. When node is touched, I think it moves to the NextVC, but I only get a black screen.
// EDIT: The solution:
func presentNextVC() {
let vc = UIStoryboard(name: "Main", bundle:nil).instantiateViewControllerWithIdentifier("NextVc") as UIViewController
let currentViewController = (UIApplication.sharedApplication().delegate as AppDelegate)
currentViewController.window?.rootViewController?.presentViewController(vc, animated: true, completion: nil)
}

Resources