How to set UINavigationController as root from UITabBarController.? - swift

I am working on App where Login is shown to user, after successful login user is landed on dashboard. where 4 tabs are shown to navigate to respective use.
I have to use, UITabBarController for four tabs from dashboard and UINavigationController for navigation from LoginView.
I set my UITabBarController to navigationController, when user successfully logged in.
Each view will have one logout button, on click of which I have to set my navigationcontroller back to root.
Here is code sample which I have done.
My UITabBarController
class TabBarVC: UITabBarController {
let dashboardViewObj = DashboardVC()
let registerViewObj = RegisterVC()
let alertViewObj = AlertVC()
let historyViewObj = HistoryVC()
override func viewDidLoad() {
super.viewDidLoad()
self.viewControllers = [dashboardViewObj, registerViewObj,historyViewObj,alertViewObj]
// Do any additional setup after loading the view.
dashboardViewObj.tabBarItem = UITabBarItem(tabBarSystemItem: .search, tag: 0)
registerViewObj.tabBarItem = UITabBarItem(tabBarSystemItem: .history, tag: 0)
historyViewObj.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 0)
alertViewObj.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 0)
}
In my LoginViewContoller
let tabbarObj = TabBarVC()
#IBAction func loginBtnClicked(_ sender: Any) {
self.navigationController?.setViewControllers([tabbarObj], animated: true)
}
Now on click of logout button from any of these views, I need to set navigationController as root.
How to do it...?
Following chart will help to understand what I need.
Any help will be appeciated.

#frzi :- Thank you very much for answers and correction from comment section.
I just did what you suggested.
The following line is corrected in my LoginViewController.
self.navigationController?.setViewControllers([tabbarObj], animated: true)
To updated line as
self.navigationController?.pushViewController(tabbarObj, animated: true)
And on Logout button action just added the line,
self.tabBarController?.navigationController?.popViewController(animated: true)
and it worked...
Cheers J...

You can use unwind segue easily instead of setting the root view controller or pop view controller or even dismiss methods!
See this for full description

When you are login all you need to put this code in your logout button action and it will redirect you to login page.
var window: UIWindow?
let appDelegate:AppDelegate = UIApplication.shared.delegate as! AppDelegate
let VC = self.appDelegate.storyboard1.instantiateViewController(withIdentifier: "Your controller name") as! loginViewController
self.appDelegate.navigationController = UINavigationController(rootViewController: VC)
self.appDelegate.navigationController?.navigationBar.isHidden = true
self.appDelegate.window?.rootViewController = self.appDelegate.navigationController
self.appDelegate.window?.makeKeyAndVisible()
it will work.

Related

My UIViewcontroller is not filling the entire screen?

I have a very simple app with two UIviewcontrollers. I want to dismiss one and present another one. However, when I do this (code below), the second viewcontroller does not fill the screen, instead it hovers over the top one and can easily get dismissed if you swipe from the top down (you can just about see the first viewcontroller at the top)?
VC-1:
#objc private func picksAction(){
print("picks button pressed")
let layout = UICollectionViewFlowLayout()
let viewController = GridPicksCollectionViewController(collectionViewLayout: layout)
let navController = UINavigationController()
navController.pushViewController(viewController, animated: true)
self.present(navController, animated: true) {}
}
Result:
Set modalPresentationStyle to .fullScreen:
navController.modalPresentationStyle = .fullScreen

TabBar controls the NavigationBar

I added 2 ViewControllers into a TabBar, but now, the TabBar's NavigationBar 'took over' each view's NavigationBar.
I can't set a title for each one of them, I can't add buttons, nothing.
I tried a few solutions to solve it that I found on the internet, but nothing worked.
I need control over the NavigationBar of each one of the views, as I need them to be different, with different title, etc.
This is my TabBar code:
class TabBar: UITabBarController {
let homeVC = HomeVC()
let followingVC = FollowingVC()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.appColors.mainWhite]
navigationController?.navigationBar.tintColor = UIColor.appColors.mainWhite
navigationItem.setHidesBackButton(true, animated: false)
homeVC.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 0)
followingVC.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 1)
let tabBarList = [homeVC, followingVC]
viewControllers = tabBarList
}
}
I really need the option to configure each NavigationBar from it's own ViewController, or atleast from the TabBar class.
You should add UINavigationController to each of your ViewControllers not your UITabBarController
First remove the UINavigationController of your TabBar, Either you have done this pragmatically or in the storyboard remove that first.
Second add UINavigationController to you ViewControllers
class TabBar: UITabBarController {
let homeVC = HomeVC()
let followingVC = FollowingVC()
override func viewDidLoad() {
super.viewDidLoad()
homeVC.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 0)
followingVC.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 1)
let homeNavigationController = UINavigationController(rootViewController: homeVC)
let followingNavigationController = UINavigationController(rootViewController: followingVC)
let tabBarList = [homeNavigationController, followingNavigationController]
viewControllers = tabBarList
}
}
Now if you change any properties like title and barButtons it will reflect accordingly.
Figured it out, the solution is:
The NavigationBar was not the TabBar navigation bar, but the screen that lead to the TabBar (Login Screen for example), I fixed it by hidding the navigation bar of the login screen when transfering to the TabBar controller, now the navigation bar of each view controller is shown and not blocked by the Login Viewcontrolelr navigationbar.

Present viewcontroller with tabbar

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?

How can I fix my navigation bar back button?

Hi I've been trying to change my back button in my application's navigation bar. The problem is that I see the change when I load the view twice.
I've searched for the answer several times but I don't see what I really want. In fact, I'm new at this language so it's difficult.
What I tried is putting the following lines in the viewWillAppear method and others*:
nav?.navigationBar.backItem?.title = "Messages"
The result is that when I enter the view I see the back button's title as Back. Then if I press on that button and enter the view again the title changes as I want. On the other hand, what I want is to change the title when I load the view first.
*-> I've tried the same line in viewDidLoad too see if that does anything and in viewWillDisappear of the previous view, but nothing happens.
You are using method a change back button in your current ViewController it is wrong, because your navigationBar configured in past controller. If you use Storyboard, please will try this method in your parent controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let backItem = UIBarButtonItem()
backItem.title = "Messages"
navigationItem.backBarButtonItem = backItem
}
If you init newController in your parentController, you must to modify your a backButton in parentController, example:
// It's action for any button witch present your newController
#objc private func presentDetailViewContorller() {
let weatherDetailController = WeatherDetailController()
let navController = NavigationController(rootViewController: weatherDetailController)
let backItem = UIBarButtonItem()
backItem.title = "Messages"
navController.backBarButtonItem = backItem
self.present(navController, animated: true, completion: nil)
}
Good luck!

Present below current view and not above

I'm trying to present a view controller below another presented view controller (like WhatsApp when you open camera and press gallery).
I tried many things but none worked ..
Use child view controller and set view of that added child view controller at the top of hierarchy. It will be top most element, so actual background of this view will be obscured, but that's the way to go.
//code inside UIViewController class
func addViewControllerAtBottom() {
let newVC = NewVCType() //just instantiate it
addChildViewController(newVC)
view.insertSubview(newVC.view, at: 0) //at 0 means it's first rendered, all others will be on top of it
}
You can reproduce this behavior by doing the following :
First, create a NavigationController with a root ViewController :
let navController = UINavigationController(rootViewController: firstController)
Then, present this navigationController with animated: false and in the completion of the present method, push your second ViewController, still with animated: false (to avoid weird animations) :
present(navController, animated: false) {
navController.pushViewController(secondController, animated: false)
}
Here you go, you got a new navigation with 2 UIViewController, like WhatsApp.
Full code, wrapped into a button's action :
#IBAction func buttonTapped(_ sender: Any) {
let navController = UINavigationController(rootViewController: firstController)
present(navController, animated: false) {
navController.pushViewController(secondController, animated: false)
}
}