TabBar controls the NavigationBar - swift

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.

Related

How can I present inside a tab of a UITabBarViewController?

I want to be able to create a TabBarViewController with some tabs and then push into the given tabs
let tabBarViewController = UITabBarController()
let redVc = UIViewController()
redVc.view.backgroundColor = .red
let blueVc = UIViewController()
blueVc.view.backgroundColor = .blue
tabBarViewController.viewControllers = [redVc, blueVc]
This created a tabBarViewController with a red and a blue tab. Now I want to push a yellow VC to the red tab so that I have a yellow and a blue tab.
let yellowVc = UIViewController()
yellowVc.view.backgroundColor = .yellow
tabBarViewController.modalPresentationStyle = .fullScreen
// this doesn't work
viewController.present(tabBarViewController, animated: true)
// must use this
tabBarViewController.viewControllers![0] = yellowVc
What should I do to be able to present in a given tab?
You can setup your UITabbarController in such a way, that each of it's child is a UINavigationController.
All together, you then have the following hierarchy:
UITabbarController
child1 (UINavigationController)
first content ViewController
child2 (UINavigationController)
second content ViewController
Now from within each contentViewController, you can use navigationcontroller.push to push a new viewController to the stack and it will stay inside the tabbar.

Display title on modally presented view in Swift 5

I am using Xcode 11.2.1, Swift 5, and have a view that is presented Modally. Via storyboard I added a navigation bar and have two navigation items, left, cancel, right, save. I am trying to get the title of the view to display. I have tried via viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "New " + costumeChoice
imageFromFileButton.alpha = 0.5
imageFromFileButton.isEnabled = false
costumeImageView.image = UIImage(named: "PauPlaceholder")
}
I have tried "self.navigationItem.title = "New " + costumeChoice" through viewWillAppear and through viewDidAppear, but no luck.
What am I missing?,
You have to present the NavigationController which embedded your ViewController, that way a navigationBar will be presented.
For example:
Assuming that your current ViewController is CurrentViewController
and viewController which you want to present is DestinationViewController
In order to present the destinationController you have to do this: -
// self ==> CurrentViewController
self.present(UINavigationController(rootViewController:DestinationViewController(), animated: true)

Swift - Expand ViewController behind the TabBar

I created three tabItems in UITabBarViewController which is pushed to another UINavigationController. One of the three tabItems is a UINavigationController, the other two are UIViewController. In order to make sure there is only one navigation bar is shown when it is in non-root viewController of the tabItem which is a UINavigationController, the parent UINavigationBar will be hidden.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navigationC = self.navigationController, navigationC.viewControllers.count == 1 {
self.navigationController?.setNavigationBarHidden(true, animated: false)
self.parent?.navigationController?.setNavigationBarHidden(false, animated: false)
} else {
self.navigationController?.setNavigationBarHidden(false, animated: false)
self.parent?.navigationController?.setNavigationBarHidden(true, animated: false)
}
self.setupViewConstraints()
}
The issue here is, if I navigate to the 2nd UIViewController of the UINavigationController, then switch from UINavigationController to UIViewController and back to the UINavigationController, the bottom of the UINavigationController is moved up which should equal to the bottom of the UIScreen. If I navigate back to the root view of the UINavigationController, the bottom of the UINavigationcontroller is equal to the UIScreen which is correct.
How can I make sure all UIViewControllers' bottom in the navigationController is equal to UIScreen? It may due to there are two navigationBar in the non-root viewController of UINavigationController tabItem.
Below is the code I used to create UITabBarViewController:
override func viewDidLoad() {
super.viewDidLoad()
tabBar.tintColor = UIColor.fromHexString("0078d7")
tabBar.barTintColor = UIColor.white
let firstViewController = FirstViewController()
firstViewController.delegate = self
firstViewController.tabBarItem = UITabBarItem.init(title: "first", image: , tag: 0)
let secondViewController = SecondViewController()
secondViewController.delegate = self
secondViewController.tabBarItem = UITabBarItem.init(title: "second", image: , tag: 1)
let thirdViewController = ThirdViewController()
thirdViewController.delegate = self
thirdViewController.tabBarItem = UITabBarItem.init(title: "third", image: , tag: 3)
let initialNavigationController = UINavigationController(rootViewController: firstViewController)
initialNavigationController.navigationItem.title = ""
self.addChildViewController(initialNavigationController)
self.addChildViewController(secondViewController)
self.addChildViewController(thirdViewController)
self.navigateToLastVisitedViewController(navigationController: initialNavigationController)
}
In above viewDidLoad method of UITabBarViewController just make your tabBar translucent. This will allow you content viewController to lay beneath UITabBar object.
Swift
self.tabBar.isTranslucent = true
Objective-C
[self.tabBar setTranslucent:YES];
Same logic will be use in UINavigationBar case.

Xcode 8, adding UIButtons to NavigationBar for non initial view controllers

I'm trying to achieve what I think would be a simple task, but despite similar posts on here being answered, the solution eludes me....
I'm using Main.storyboard in Xcode 8/swift 3 to create an application with the initial ViewController being a UINavigationController. I then want to push to UITabBarController which has two view controllers which it holds a relationship with:
override func viewDidLoad() {
super.viewDidLoad()
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let vc = mainStoryboard.instantiateViewController(withIdentifier: "test") as? UITabBarController {
self.navigationController?.pushViewController(vc, animated: true)
}
}
When launching the app, the initial ViewController successfully 'pushes' to the TabBarController/it's ViewControllers (image below). The issue I'm having is after adding navigation items/buttons in the TabBarController ViewControllers (either in Storyboard or programmatically) the buttons / nav items never show.
Storyboard setup
Simulator screenshot
I have seen a few posts such as the below links and have followed the suggested steps verbatim, but nothing has solved the problem. Any help would be greatly appreciated!
Adding buttons to navigation controllers
How to add buttons to navigation controller visible after segueing?
It's does not show, because your TabBarController also have his own UINavigationBar. ViewControllers are inside TabBarController
you can create custom TabBarController and handle tabs actions
Try this code:
class TabBarController: UITabBarController {
override var selectedViewController: UIViewController? {
didSet {
switch self.selectedViewController {
case self.selectedViewController is FirstViewController:
self.navigationItem.rightBarButtonItem = self.firstButton
case self.selectedViewController is SecondViewControlller:
self.navigationItem.rightBarButtonItem = self.secondButton
default:
break
}
}
}
}

Programmatically create a navigation view

So I'm trying to create an app but I'm trying to avoid the use of storyboards. Hence just using swift files along with XIB files.
I have worked a little with Navigation controllers before but not enough I guess. So far I have this:
In AppDelegate I have:
let homeVC = HomeViewController()
let rootVC = UINavigationController(rootViewController: homeVC)
window!.rootViewController = rootVC
window!.makeKeyAndVisible()
My view currently is entirely empty, but with the basic "View" screen that comes with creating a new XIB file. I've set the size of that to freeform, and all other things like Top Bar, Status Bar are Inferred.
In my HomeViewController.swift I have:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let nib = UINib(nibName: "HomeView", bundle: nil)
let objects = nib.instantiateWithOwner(self, options: nil)
self.view = objects[0] as! UIView;
print(self.navigationController)
// customize navigation bar
let settingsImage = UIImage(named: "settingsWheelBlack.png")
let settingsNavItem = UIBarButtonItem(image: settingsImage, style: UIBarButtonItemStyle.Plain, target: nil, action: Selector("selector"))
let addStuffItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: nil, action: Selector("selector"))
self.navigationController?.navigationItem.title = "Home"
self.navigationController?.navigationItem.leftBarButtonItem = settingsNavItem
self.navigationController?.navigationItem.rightBarButtonItem = addStuffItem
print(self.navigationController?.navigationBar)
print(self.navigationController?.navigationItem.title)
}
But when I run the application the navigation bar doesn't show up. Here's what I've tried besides what I currently have:
Add a Navigation Bar control to my XIB and connect an IB outlet to it. Also connect the IB outlet to the navigation item that already exists in the navigation bar control. Then set the title, and left and right buttons in that. Didn't work
Set the title and buttons in AppDelegate straight away for the rootVC defined above. Didn't work.
Any ideas what I'm missing?
I solved this after gathering some strength to read through tons of Apple docs. On this page I found this small piece of text:
In a navigation interface, each content view controller in the navigation stack provides a navigation item as the value of its **navigationItem** property. The navigation stack and the navigation item stack are always parallel: for each content view controller on the navigation stack, its navigation item is in the same position in the navigation item stack.
So I left my AppDelegate code as is and changed me viewDidLoad function to:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let nib = UINib(nibName: "EventsHomeView", bundle: nil)
let objects = nib.instantiateWithOwner(self, options: nil)
self.view = objects[0] as! UIView;
print(self.navigationController)
// customize navigation bar
let settingsImage = UIImage(named: "settingsWheelBlack.png")
let settingsNavItem = UIBarButtonItem(image: settingsImage, style: UIBarButtonItemStyle.Plain, target: nil, action: Selector("selector"))
let addStuffItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: nil, action: Selector("selector"))
// Each VC within a navigation controller has it's own navigationItem property that the underlying navigation controller uses to show in the navigationBar
self.navigationItem.title = "Home"
self.navigationItem.leftBarButtonItem = settingsNavItem
self.navigationItem.rightBarButtonItem = addStuffItem
}
And viola!