Im trying to process a navigation inside a reusble func i cannot get it to work this is the code i have so far.
static func navigationBarShow() {
let navigationCoontroller = UINavigationController()
navigationCoontroller.navigationBarHidden = false
navigationCoontroller.navigationBar.barTintColor = UIColor(red:0.4, green:0.76, blue:0.93, alpha:1.0)
navigationCoontroller.navigationBar.translucent = false
navigationCoontroller.title = "Signup"
navigationCoontroller.navigationBar.tintColor = UIColor.whiteColor()
navigationCoontroller.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
}
Try writing it as an extension to UINavigationController and use self as the navigation controller. You are creating a new UINavigationController instance each time you want to display a navigation bar and that instance is never being displayed on the screen.
extension UINavigationController {
func showNavigationBar() {
self.navigationBarHidden = false
self.navigationBar.barTintColor = UIColor(red:0.4, green:0.76, blue:0.93, alpha:1.0)
self.navigationBar.translucent = false
self.title = "Signup"
self.navigationBar.tintColor = UIColor.whiteColor()
self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
}
}
Then, from any UINavigationController, you can call showNavigationBar().
Update:
In the code for any subclass of UIViewController that is embedded in a UINavigationController, call navigationController!.showNavigationBar().
For example:
class MyViewController: UIViewController {
override func viewDidLoad() {
self.navigationController!.showNavigationBar()
}
}
Note that the ! assumes your view controller is embedded in a navigation controller. If any vc is not embedded in a navigation controller but you want a navigation bar, you should consider embedding it in a navigation controller.
This line:
let navigationCoontroller = UINavigationController()
creates a brand-new navigation controller every time you run it.
Unless the code you posted is run once and only once, that's wrong, since every time you call that function you create a new navigation controller
Related
I tried adding a split view controller with triple column style to a UITabBarController and it shows up in collapsed state. The same code works fine when I use the older style of the split view controller. How do I get the 3-column split view controller to show up correctly on a tab bar controller?
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// This works fine 🤷♂️
let splitViewController = SplitViewController()
splitViewController.viewControllers = [ UINavigationController(rootViewController: PrimaryViewController()) , UINavigationController(rootViewController: SecondaryViewController())]
// let splitViewController = SplitViewController(style: .tripleColumn)
// splitViewController.setViewController(UINavigationController(rootViewController: PrimaryViewController()), for: .primary)
// splitViewController.setViewController(UINavigationController(rootViewController: SecondViewController()), for: .secondary)
// splitViewController.setViewController(UINavigationController(rootViewController: SupplementaryViewController()), for: .supplementary)
// splitViewController.show(.primary)
// splitViewController.show(.secondary)
// splitViewController.show(.supplementary)
splitViewController.title = "First"
let secondViewController = SecondViewController()
secondViewController.title = "Second"
setViewControllers([
splitViewController,
secondViewController
], animated: false)
}
}
here is the link to the project: https://github.com/anirudhbandi96/SplitViewTest
This is how the new three column split view controller looks
This is how the old 2-column split view controller looks
I couldn't even get the 2 column one to work inside a UITabBarController. But, if I just make a new UIViewController, that adds as a childViewController a UISplitViewController, then everything works just fine.
class MyViewController: UIViewController {
let split = UISplitViewController(style: .doubleColumn)
override func viewDidLoad() {
super.viewDidLoad()
addChild(split)
view.addSubview(split.view)
// add in your constraints to fix to same size here
// -- here --
split.didMove(toParent: self)
}
}
I have a tabBarController under which I loaded some navigation controller. But the title of my navigation controller is not showing up. Even I noticed if I add buttons in my left and right navbar item, it doesn't show up as well.
My Tabbar Setup:
let quranNavigationController = UINavigationController()
// quranNavigationController.navigationBar.titleTextAttributes = textAttributes
// quranNavigationController.navigationBar.tintColor = Colors.primaryTextColor
// quranNavigationController.navigationBar.barTintColor = Colors.navigationBackgroundPrimary
let quranSnackBarController = AppSnackbarController(rootViewController: quranNavigationController)
quranSnackBarController.shouldExtend = false
quranSnackBarController.tabBarItem = UITabBarItem(title: "Books".localized(), image: UIImage(named: "quran"), tag: 1);
let menuViewController = TestViewController()
let quranController = QuranPrintController()
let sideMenuController = SideMenuController(contentViewController: quranController, menuViewController: menuViewController)
quranNavigationController.viewControllers = [sideMenuController]
tabBarController.viewControllers = [homeNavigationController2, quranSnackBarController, prayerNavigationController, duaSnackBarController]
window.rootViewController = tabBarController
QuranPrintController:
class QuranPrintController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Quran"
self.navigationItem.title = "Prayer Times"
}
}
This is what my output is. No title is shown. I tried adding buttons on the left and right sides. But didn't work as well
First make sure your tabbarcontroller is embedded with navigation controller and then your all controllers are connected with your navbar
like this
then embed your navigation controllers with your each view controller with seperate navigController
Try Add this in your ViewdidLoad() .
self.view.bringSubviewToFront(yourbuttonname)
I have subclassed UITabBarController to allow for some customization specific to my app. It is the root view controller of my UIWindow and displays itself correctly on launch, and even shows the correct tab's view hierarchy as well.
The problem is with the selected tabbar item's tint color. Inside viewDidLoad of the custom tab bar controller subclass, I have set both the unselected and selected tint colors for the tab bar. See below:
override func viewDidLoad() {
super.viewDidLoad()
tabBar.tintColor = .tabBarItemActiveTint
tabBar.unselectedItemTintColor = .tabBarItemInactiveTint
tabBar.barTintColor = .tabBarBg
let dashboardVC = DashboardViewController.build()
let settingsVC = SettingsTableViewController.build()
let settingsNavC = UINavigationController(rootViewController: settingsVC)
settingsNavC.navigationBar.barStyle = .black
viewControllers = [dashboardVC, settingsNavC]
selectedViewController = dashboardVC
// Accessing the view property of each tab's root view controller forces
// the system to run "viewDidLoad" which will configure the tab icon and
// title in the tab bar.
let _ = dashboardVC.view
let _ = settingsVC.view
}
As you can see, the controller has its child view hierarchies set, and the views are loaded at the bottom so their respective viewDidLoad methods run where I have code that sets the tabBarItem. Here's an example from the dashboard view controller:
tabBarItem = UITabBarItem(title: "Dashboard", image: UIImage(named: Theme.dashboardTabBarIcon), tag: 0)
Everything about this works except for the selected icon and title. When the app launches I can see the tab bar, the first view hierarchy (the dashboard) is visible onscreen and the tabs all function properly. But the dashboard's icon and title are in an unselected state. I have to actually tap the tab bar icon to get the state to change such that it is selected.
Once you tap one of the tabs, the selected state works as normal. The issue is only on the first presentation of the tab bar.
Here is an image showing the initial state of the tab bar on launch. Notice the dashboard icon is not selected, even though it is the presented view controller.
UPDATE
Skaal's answer below solved the problem for me.
For future reference: the key difference between the code presented here in my question and his sample in the answer is that the tabBarItem is set in viewDidLoad of his custom TabBarController class. By contrast, that code was placed within the viewDidLoad method of each constituent view controller class in my project. There must be a timing issue of when things are called that causes the tint color to not be set in one scenario and work properly in the other.
Key Takeaway: If you set up a tab bar controller programmatically, be sure to set your tabBarItem properties early on to ensure tint colors work properly.
You can use :
selectedIndex = 0 // the index of your dashboardVC
instead of selectedViewController
EDIT - Here is a working sample of UITabBarController:
class TabBarController: UITabBarController {
private lazy var firstController: UIViewController = {
let controller = UIViewController()
controller.title = "First"
controller.view.backgroundColor = .lightGray
return controller
}()
private lazy var secondController: UIViewController = {
let controller = UIViewController()
controller.title = "Second"
controller.view.backgroundColor = .darkGray
return controller
}()
private var controllers: [UIViewController] {
return [firstController, secondController]
}
override func viewDidLoad() {
super.viewDidLoad()
tabBar.tintColor = .magenta
tabBar.unselectedItemTintColor = .white
tabBar.barTintColor = .black
firstController.tabBarItem = UITabBarItem(title: "First", image: UIImage(), tag: 0) // replace with your image
secondController.tabBarItem = UITabBarItem(title: "Second", image: UIImage(), tag: 1) // replace with your image
viewControllers = controllers
selectedViewController = firstController
}
}
I need to make the navigation bar in some view controllers transparent (but with the bar buttons visible).
I wrote the following extension for that.
extension UINavigationBar {
func setTransparent(_ flag: Bool) {
if flag == true {
setBackgroundImage(UIImage(), for: .default)
shadowImage = UIImage()
backgroundColor = .clear
isTranslucent = true
} else {
setBackgroundImage(nil, for: .default)
}
}
}
The default styles for my navigation bars are as follows.
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().tintColor = .white
UINavigationBar.appearance().barTintColor = UIColor(red: 45/255, green: 93/255, blue: 131/255, alpha: 1)
UINavigationBar.appearance().titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
All this works fine. But there's a problem if I have to turn off the transparent effect.
Say in the first view controller I don't need the navigation bar to be transparent.
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.setTransparent(false)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.isTranslucent = false
}
}
I push to the second view controller from here. In here, the navigation bar is transparent.
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.setTransparent(true)
}
}
Now when I pop back to the previous view controller, I have to explicitly set the isTranslucent property to false. I do that in the viewWillAppear as you can see in the first code snippet.
But the problem is, the navigation bar is black for a second when it happens.
I want this to be smooth. How do I avoid this?
Demo project uploaded here.
I tried the solution described here to a similar question. But it doesn't completely fix my issue. The black bar is gone but the navigation bar doesn't appear for a second just like before as you can see here.
Black navigation bar you see is actually a navigation controller view background color. Try add this code in first view controller viewDidLoad method
navigationController?.view.backgroundColor = navigationController?.navigationBar.barTintColor
Setting the navigation controller view background color did fix the black issue for me, but I was still having the "delay" problem when popping a view controller.
I fixed it by changing the theme of my NavigationController on the willMove method of the view controller being popped. Something like this:
override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent: parent)
guard parent == nil,
let navController = self.navigationController else {
return
}
navController.navigationBar.isTranslucent = false
navController.view.backgroundColor = backgroundColor
navController.navigationBar.barTintColor = barColor
navController.navigationBar.tintColor = tintColor
}
Before Push I use
if let navigator = self.navigationController {
navigator.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigator.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor : UIColor.black]
navigator.pushViewController(viewController, animated: true)
}
this make the glitch disappear working fine...
note in my case background color was white
I am performing a segue from my loadVC to containterVC in which I set up a navigationController and set it's rootViewController to mainVC
Code in viewDidLoad in containterVC:
override func viewDidLoad() {
super.viewDidLoad()
mainVC = UIStoryboard.mainVC() //This is an extension to UIStoryboard
//Setting up the delegate:
mainVC.delegate = self
//rootViewController - ten najbardziej na dole
myNavigationController = UINavigationController(rootViewController: mainVC)
//Storing the root view as currentViewController:
self.currentViewController = mainVC
myNavigationController.addChildViewController(mainVC)
self.view.addSubview(myNavigationController.view)
addChildViewController(myNavigationController)
myNavigationController.didMoveToParentViewController(self)
//Trying to set up the navigation bar
let bar = myNavigationController.navigationBar
//Navigation bars:
bar.barTintColor = UIColor.blackColor()
bar.tintColor = UIColor.whiteColor()
bar.translucent = false
}
I launch the project. And? Everything works properly.
Then I try to add these under "bar.translucent = false" line:
print("statement1")
let menuButton = UIBarButtonItem(title: "Menu", style: UIBarButtonItemStyle.Plain, target: self, action: "")
print("statement2")
let item = myNavigationController.navigationItem
print("statement3")
item.leftBarButtonItem = menuButton
print("statement4")
bar.items = [item]
print("statement5")
After launching the project print statements up to 4 are displayed and the 5th is not. So it seems that the segue between loadVC and containterVC is done, but I don't see the mainVC screen that was set up as a rootViewController.
When I delete "bar.items = [item]" line the project is run as it should be, but there is no "Menu" button in the navigation bar.
What am I doing wrong?
You can just use a "container view" from the storyboard and embed a UINavigationController with your mainVC directly within the storyboard.
Anyway i think that myNavigationController.addChildViewController(mainVC) not necessary.
Also the bar items should be set to the mainVC's navigationItem, not the navigationController's one.
Also you did not mention what kind of segue are you using.