I have a storyboard I'm working with that is setup as so:
Login Screen -> Tab Bar Controller - > Navigation Controller - > Screen 1 Segue to Screen 2 Segue to Screen 3.
The first time I login, everything works great. Screen 1 segues to screen 2, screen 2 segues to screen 3, you can then use the back button to go back to screen 2 and then screen 1. However, I have a "logout" function (code below, although I don't think this is relevant to my issue) and after I "logout", it takes me to the Login Screen (first screen in the sequence above). When I then login again, navigate to Screen 2 or Screen 3, pressing the back button from the segue takes me all the way back to the login screen as opposed to the prior Screen 1 or Screen 2.
#objc func logOut(){
let homeView = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.navigationController?.pushViewController(homeView, animated: true)
homeView.navigationItem.hidesBackButton = true
}
I'm not sure that instantiating the LoginViewController again is the best practice, since you already have it in you navigation stack. I would recommend doing something like this:
#objc func logOut(){
self.navigationController?.popToRootViewControllerAnimated(true)
}
This will remove all the view controllers from the navigtion stack, and present you with a root view controller (LoginViewController)
Updated for anyone who is curious. The pushViewController option was the issue. If i just use "present", I no longer have this issue. Here is my updated logout code:
#objc func logOut(){
let homeView = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.navigationController?.present(homeView, animated: true)
homeView.navigationItem.hidesBackButton = true
}
Related
In my project you can create a post from a modal view.
When the modal view is dismissed (user presses on save post) I want to switch the tab bar controller to the second tab (post feed screen).
This topic is similar to my problem. The only difference being this is presented from a modal view. I can't figure out how to implement it in my code (tab bar is nil)
Switch tab bar programmatically in Swift
I have added 3 images to make this issue clearer
code screenshot
console message
#objc func saveAction(sender: UIButton) {
print ("> save pressed")
print(presentingViewController?.tabBarController)
print(presentingViewController)
presentingViewController?.tabBarController?.selectedIndex = 1
dismiss(animated: true)
}
edit: sorry stack overflow doesn't allow me to add images yet
You can do this using delegate pattern. But if you prefer not to add a delegate for this, you can do as shown below;
You can switch the tabbar by changing the selectedIndex property of tabBarController
if let presenter = presentingViewController as? LibraryViewController {
presenter.tabBarController?.selectedIndex = 1
}
dismiss(animated: true)
If you are presenting the modal on navigation controller in tabbar, use:
if let tabBar = presentingViewController as? UITabBarController {
tabBar.selectedIndex = 1
}
dismiss(animated: true)
I created UITabBarController programmatically in AppDelegate with 4 view controllers(using .xib). When user tap some button on ViewController (VC-A) it present another VC (VC-B) and covered tabbar. So I want to VC-B has a tabbar on the button.
I tried to add VC-B as a child of tabbarcontroller. I tried to .present(vc) and .show(vc) on both: VC-A and VC-A.TabBarController
Creating controllers in AppDelegate:
let controllers = [tabViewController1,tabViewController2,tabViewController3,tabViewController4]
tabBarController.viewControllers = controllers
window?.rootViewController = tabBarController
presenting in VC-A
self.tabBarController?.present(controller, animated: false, completion: nil)
right click and drag from tabbar controller in storyboard to VC-B. that should create a tab on the bottom of your VC-A and VC-B to go back and forth without having to implement any backend code unless you want to animate
The solution is to embed every VC in navigationController and then add to TabBarController.
let vc1 = ViewController1()
let navController1 = UINavigationController(rootViewController: vc1)
navController.isNavigationBarHidden = true
let controllers = [navController1, navController2, navController3, navController4]
tabBarController.viewControllers = controllers
window?.rootViewController = tabBarController
Then call
self.navigationController?.pushViewController(controller, animated:
true)
To diplay VC with tabbar
I will press the red login button at the bottom of the picture and try to log in.
login button => "로그인"
After that, log in.
let moreVC = self.storyboard?.instantiateViewController(withIdentifier: "MoreViewController") as! MoreViewController
moreVC.definesPresentationContext = true
moreVC.modalPresentationStyle = .fullScreen
let navController = UINavigationController(rootViewController: moreVC)
self.present(navController, animated: true, completion: nil)
If the login proceeds without error, the above code will be called to display the screen when the login is completed.
If the flow proceeds as the code above, this screen appears.
The screen shown is not fullscreen, and the tabbar at the bottom is gone. The screen I want is the screen below.
How can I present a tab bar when presenting the screen?
I have programatically set up a custom UITabBarControler with three tabs, each of which is a UIViewController embedded a UINavigationController.
I am not using storyboards. I set the custom tab controller as the root in AppDelegate
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = CustomTabBarController()
The app runs fine and I get the three tabs and can move between them.
sample of how tabs are populated (in viewDidLoad of the customer tab bar controller)
let ordersVC = OrdersViewController() // where Orders is a UIViewController
ordersVC.title = "Orders"
ordersVC.view.backgroundColor = UIColor.white
let ordersVCNavi = UINavigationController(rootViewController: ordersVC)
ordersVCNavi.navigationBar.tintColor = UIColor.black
...
viewControllers = [homeVCNavi, inventoryVCNavi, ordersVCNavi]
Now I need to first to see if the user is logged in (using Firebase). I can easily check for already logged in (Firebase cached) or not logged in.
I do this logged in check in AppDelegate
My problem is when I need to force a login (jump to login view controller). I can not find a place that works.
- tried placing the call in the custom UITabBarController didLoad and the code is ignored
- tried placing the call in the didLoad and the willAppear in the initial tab controller also ignored
I can place a button on the initial tab and that button will indeed launch the login controller. So I can get to the login controller from a button press.
upon pressing a button I can execute this code and the login controller will show
let vc = LoginViewController()
self.navigationController?.pushViewController(vc, animated: false)
But if I know I need to force login and I try to do that same code snip above in viewDidLoad() or viewWillAppear() in the initial tab controller, or in the custom UITabBarController then the push is ignored. Nothing happens.
What is best practice for forcing login screen when initial view is tabbarcontroller?
Where should one put the navigation to the login controller to force login when not already logged in. Want to go to login so that user can not use the app if not logged in.
in didFinishLaunchingWithOptions
if loggedIn {
window?.rootViewController = CustomTabBarController()
}
else {
window?.rootViewController = LoginViewController()
}
after your login is successful
UIApplication.shared.keyWindow?.rootViewController = CustomTabBarController()
i have some navigations controller
Navigation Controller 1
Navigation Controller 2
when the user log off (red box), should be back to screen log in (yellow box)
two navigation controllers are involved, the first one that is in the red box must die completely, just like that tab bar that is included.
this is the code of the close session button.
#IBAction func CerrarSesion(_ sender: Any)
{
do
{
try Auth.auth().signOut()
let vc = self.storyboard?.instantiateViewController(withIdentifier: "InicioSesionLogin")
//self.dismiss(animated: true, completion: nil)
self.present(vc!, animated: true, completion: self.borrarUserDefaults)
}
catch let error as NSError
{
print (error.localizedDescription)
}
}
this code returns me to the view of logging in without a issue, but the views that are ahead are still working, I know because there is a view that uses location functions of beacons, and leave a function that prints ("ranging").
In summary: I want to return to the view to log in (red box) and kill all the views that I have in front of me.
the only thing I could do, is to kill the first navigation controller (yellow box) but it returns me to a back view, where you see the gray box.
if the navigation controller is the rootVc , you can reset it's viewcontrollers property
self.navigationController.viewControllers = [VC]
or reset the rootVC
UIApplication.shared.keyWindow?.rootViewController = // VC
I have a tab bar controller in my app. one of the tabs has a navigation Controller with a bar button. clicking the bar button segues to a tableViewController which has another button in it. The button segues to yet another TableViewController which includes a logout button.
#IBAction func logoutDidTap(_ sender: Any) {
try! FIRAuth.auth()?.signOut()
when I login to the app again and click on that tab, it takes me to the TableViewController with the logout button instead of the beginning of the tab. How can I fix this?
Since you have placed all the view controllers under the navigation controller, so you can easily pop them from the navigation stack when you are done logging out. Here's how to do it:-
#IBAction fund logoutDidTap(sender:Any){
try! FirAuth.auth()?.signout()
var viewControllers = navigationController?.viewControllers
viewControllers?.removeLast(2) // views to pop
navigationController?.setViewControllers(viewControllers!, animated: true)
}