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.
Related
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 would like to integrate both navigation controller and tab bar controller in my project.But I am unable to add right barbutton to the navigation controller.
I have attached the screenshot of the storyboard
What I have done is I have added navigation controller to login screen and this time I am able to add barbuttonitem both by adding code as well as by dragging barbuttonitem to navigation controller.
let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addTapped))
self.navigationItem.rightBarButtonItem = addBtn
Problem I am facing is after adding Tab bar controller I am unable to add rightbarbutton both by code as well as by dragging to the navigation controller. please help me.
When a ViewController is embedded in a NavigationController you use
self.navigationItem.rightBarButtonItem = addBtn
In your project Detail Screen isn't embedded in NavigationController directly. Detail Screen is embedded in TabBarController, TabBarController is embedded in NavigationController. So you should use
self.tabBarController?.navigationItem.rightBarButtonItem = addBtn
But this addBtn will be visible in all view controllers which are embedded in the TabBarController.
If you want to add the rightBarButton for only one viewcontroller, then embed the Detail Screen in a new NavigationController. Then you can add rightBarButton using
self.navigationItem.rightBarButtonItem = addBtn
You should be sure parent returns the top child controller of UINavigationController. In my case
parent?.parent?.navigationItem.right...
did the trick.
If you reuse the controller -as embedded or not- which you want add items to navigationItem, following example will work. However some logical changes may be needed.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard parent is UINavigationController else {
parent?.parent?.navigationItem.rightBarButtonItem = UIBarButtonItem()
return
}
navigationItem.rightBarButtonItem = UIBarButtonItem()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
guard parent is UINavigationController else {
parent?.parent?.navigationItem.rightBarButtonItem = nil
return
}
navigationItem.rightBarButtonItem = nil
}
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
}
}
When I try to present a TabViewController, I get odd behavior from both my TabBar and NavigationBar as seen in the images below. It stays as shown in the "before" image until I touch the screen or push a button. At the point it jumps to the "after" image.
Before:
After:
Code used to present the TabViewController:
let delegate = UIApplication.shared.delegate as! AppDelegate
delegate.tabViewController = TabViewController()
self.present(delegate.tabViewController!, animated: true, completion: nil)
Initialization of the TabViewController:
override func viewDidLoad() {
super.viewDidLoad()
let groupTable = GroupTableViewController()
let nav = UINavigationController(rootViewController: groupTable)
nav.title = "Groups"
nav.tabBarItem.image = UIImage(named: "groups")
let vc2 = MeViewController()
vc2.title = "Me"
vc2.tabBarItem.image = UIImage(named: "user")
// let vc3 = SettingsViewController
// vc3.title = "Settings"
// vc3.tabBarItem.image = UIImage(named: "settings")
self.viewControllers = [nav, vc2]
self.selectedIndex = 0
}
Console log, but I don't think the error is relevant:
objc[63765]: Class PLBuildVersion is implemented in both /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/AssetsLibraryServices.framework/AssetsLibraryServices (0x11916f998) and /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/PhotoLibraryServices.framework/PhotoLibraryServices (0x118069d38).
One of the two will be used. Which one is undefined.
This is a new bug I've been experiencing seemingly after updating to Xcode 8.1/MacOS Sierra.
My XCode version is Version 8.1 beta (8T47). Could this be a bug in the beta?
I'm unsure what is causing this as I didn't make a code change when this started happening.
Thanks for the help.
The viewDidLoad of the tab view controller is really too late to be configuring the tab view controller with its two child view controllers. Either do this in the "Code used to present the TabViewController", or, if you really want to do it from within the tab view controller itself, do it from the tab view controller's initializer. Then all will be well.
I know this question gets asked a lot.
I've tried every answer (I think) and can't get a title to show up.
I have a static method I use to show view controllers modally.
I think I understand that a navigation controller gets its title from the title property of the view controller it is presenting, but I cannot get my vc's title to show up, and other methods I have tried aren't working, either.
static func present(vc vc: UIViewController) {
// The navCtrl presents a vc, and uses that title.
// I should be able to set this, right?
vc.title = "vc.title" // doesn't show up
vc.navigationItem.title = "vc.navigationItem.title" // nothing
vc.navigationItem.prompt = "vc.navigationItem.prompt" // doesn't show
vc.navigationController?.title = "vc.navigationController?.title" // nuttin'
let navCtrl = UINavigationController(rootViewController: vc)
navCtrl.navigationBar.tintColor = UIColor.whiteColor()
navCtrl.navigationBar.barTintColor = UIColor.blackColor()
navCtrl.navigationBar.translucent = false
// How about adding a UINavigationItem? Nope.
// let item = UINavigationItem(title: "UINavigationItem")
// navCtrl.navigationBar.pushNavigationItem(item, animated: true) // CRASH: Cannot call pushNavigationItem:animated: directly on a UINavigationBar managed by a controller.
// Can I set something on the navCtrl? Huh-uh. None of this works
navCtrl.navigationController?.title = "navCtrl.navigationController?.title"
navCtrl.navigationItem.prompt = "navCtrl.navigationItem.prompt"
navCtrl.title = "navCtrl.title"
navCtrl.navigationItem.title = "navCtrl.navigationItem.title"
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(navCtrl, animated: true, completion: nil)
}
No matter what I've tried, I just get an empty navigation bar with a close button: