UITabbarController UITabbarItem does not appear when UINavigationController is embeded - ios

As the title says, does the UITabbarItem not appear if I embed in a UINavigationController like so:
lazy var tabBarViewController: UITabBarController = {
let tBarViewController = UITabBarController()
let firstViewController = ViewController()
firstViewController.tabBarItem.title = "Home"
tBarViewController.viewControllers = [UINavigationController(rootViewController: firstViewController)]
return tBarViewController
}()
lazy var window: UIWindow = {
let win = UIWindow(frame: UIScreen.mainScreen().bounds)
win.backgroundColor = UIColor.whiteColor()
win.rootViewController = self.tabBarViewController
return win
}()
func customizeAppereance() {
UINavigationBar.appearance().barTintColor = UIColor.themeColor()
UITabBar.appearance().barTintColor = UIColor.themeColor()
}
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
customizeAppereance()
UIApplication.sharedApplication().setStatusBarHidden(false, withAnimation: .Fade)
window.makeKeyAndVisible()
return true
}
If I remove the UINavigationController it works and the UITabbarItem is visible.
How can I embed in a UINavigationController and have the UITabbarItem to appear? (I am not using NIBs or Storyboard, just code) ?

The tab bar item has to belong to the view controller you're adding to the tab bar controller - in this case, the navigation controller. Otherwise, it tries to create one from the title (non-existent).
You need to set the tabBarItem property on the navigation controller, not its root view controller.

Related

Set UITabBarController as rootViewController

I have a UITabBarController and I want to show this screen and not the login screen if the user session is still active.
My UITabBarController has 3 ViewControllers and the problem is that I don't see the TabBar links in the bottom and I'm unable to navigate.
Without the following code everything works fine. I mean after login I can navigate.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
if Auth.auth().currentUser != nil {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = HomeTabBarController()
}
return true
}
I have also tried the following code to set the rootViewController but it's the same problem.
When I try to set one of the other view controllers as root (one of the children), the Tab Bar doesn't show at all
var rootView: MyRootViewController = MyRootViewController()
if let window = self.window{
window.rootViewController = rootView
}
What am I doing wrong here?
I was facing same issue and I came across your post, the problem with your code is that HomeTabBarController() is creating a whole new TabBarController so to fix it try the following approach I used.
if Auth.auth().currentUser != nil {
print("******************************User Present******************************")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// create view controllers from storyboard
// Interface Builder -> Identitiy Inspector -> Storyboard ID
// Set up the Tab Bar Controller to have two tabs
let tabBarController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarController") as! HomeTabBarController
// Make the Tab Bar Controller the root view controller
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
}
Edit Make sure to add the Identifier to your TabBarController
// Interface Builder -> Identitiy Inspector -> Storyboard ID
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//// this code changes the initial point of aap///////
window = UIWindow(frame: UIScreen.main.bounds)
let nav = UINavigationController()
let myview = SettingTabbar()
nav.viewControllers = [myview]
window?.rootViewController = nav
window?.makeKeyAndVisible()
return true
}
And Function SettingTabbar is:
func SettingTabbar()->(UITabBarController)
{
//Setting TabBar
let tabbar = UITabBarController()
//Designing Tabbar Item Images
let table = UITabBarItem(title: nil, image:UIImage(named: "002-list") , tag: 0)
let collection = UITabBarItem(title: nil, image: UIImage(named: "001-collect"), tag: 1)
let insert = UITabBarItem(title: nil, image: UIImage(named: "add"), tag: 2)
//Getting TabBar ViewControllers
let TableView = newViewController()
let CollectionView = PersonCollectionViewController()
let InsertRec = nextViewController()
//Setting ViewControllers on TabBar Items
TableView.tabBarItem = table
CollectionView.tabBarItem = collection
InsertRec.tabBarItem = insert
let controllers = [TableView,CollectionView,InsertRec]
tabbar.viewControllers = controllers
tabbar.viewControllers = controllers.map{UINavigationController(rootViewController: $0)}
//Setting Title
tabbar.navigationItem.title = "Person Record"
return tabbar
}
The problem is this line:
window?.rootViewController = HomeTabBarController()
That is the wrong HomeTabBarController. It is a totally new HomeTabBarController with no children. You need to fetch the HomeTabBarController that’s in the storyboard.
I finally found the solution: As #matt suggested I had to fetch the HomeTabBarController that’s in the storyboard.
window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
// controller identifier sets up in storyboard utilities
// panel (on the right), it called Storyboard ID
let viewController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarController") as! HomeTabBarController
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
window?.makeKeyAndVisible()
window?.rootViewController = viewController

UINavigationController how to set title and etc in children views

My app structure:
firstView: UIViewController with UINavigationController -- secondView UITabBarController with several UIViewControllers
start app, firstView:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let vc = ViewController()
let navContr = UINavigationController(rootViewController: vc)
self.window? = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = navContr
self.window?.makeKeyAndVisible()
return true
}
In firtView I click button to open secondView:
let vc = MyTabController() // my UITabBarController
self.navigationController?.pushViewController(vc, animated: true)
start secondView:
class MyTabController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let gen = MyViewController()
let tabGen = UITabBarItem()
gen.tabBarItem = tabGen
tabGen.image = UIImage(named: "general")
tabGen.title = "Все вопросы"
viewControllers = [gen]
....
}
In my secondView I want set Title, set UISearchControlleer in every tab. But if I write in ViewController
navigationItem.title = "myTitle" nothing changes. I see button "Back" only.
Here's the screenshot
Set title like this in viewDidLoad() Method
self.title = "Your Title"

UISplitView's MasterViewController and Navigation Issue

I am updating my existing app to include a SplitView for iPads.
I have it working with a UITabBar, but am having an issue with my masterViewController as it is generating a "duplicate" navigation bar that is covering my existing navigation items on all masterViewControllers (tabs), including searchBar on the search tab.
The code I have is:
AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
let splitViewController = self.window!.rootViewController as! UISplitViewController
splitViewController.delegate = self
splitViewController.preferredPrimaryColumnWidthFraction = 0.33
splitViewController.minimumPrimaryColumnWidth = 375
splitViewController.preferredDisplayMode = .allVisible
return true
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
return true
}
The reason for having this in the AppDelegate is I saw an example where placing it hear will allow me not to require the code in each of the different Master Views (each tab). Have yet to test this as still working on the first master view.
Master View
override func viewDidLoad()
{
self.extendedLayoutIncludesOpaqueBars = true
self.navigationItem.hidesBackButton = true
// 3D Touch
if traitCollection.forceTouchCapability == .available {
registerForPreviewing(with: self as UIViewControllerPreviewingDelegate, sourceView: view)
ThreeDTouch = true
}
self.addSwitchVewButtonToNavigationBar()
self.addCategoryButtonToNavigationBar()
}
func addSwitchVewButtonToNavigationBar() {
let switchButton = UIButton(type: UIButtonType.custom)
let editImage = UIImage(named: "CollectionButton")?.withRenderingMode(.alwaysTemplate)
switchButton.setImage(editImage, for: .normal)
switchButton.addTarget(self, action: #selector(SpeciesViewController.onSwitchView), for: UIControlEvents.touchUpInside)
let switchButtonFinal = UIBarButtonItem(customView:switchButton)
self.navigationItem.rightBarButtonItem = switchButtonFinal
}
#IBAction func onSwitchView(_ sender: UIBarButtonItem)
{
AppDelegate.getAppState().isListViewSelected = false
let speciesColletion = storyboard?.instantiateViewController(withIdentifier: Resource.SpeciesCollectionStoryboard) as! SpeciesCollectionViewController
self.navigationController?.viewControllers = [speciesColletion]
}
Originally, the onSwitchViewButton was embedded using the IB, but did not work. This is the same system used for the addFavorite on the Detail View.
The problem that you addressing wrong UINavigation controller. I assume before splitting both master and SpeciesViewController existed in same navigation environment, and use same navigation controller. But in split view they don't. Your detail controller is actually UINavigation controller you are looking for, that had to control all navigation, and had to have buttons you need. You can get it from master as:
guard let split = splitViewController, let navController = split.viewControllers.last as? UINavigationController else { return }
And make sure that you split controller not embedded into another UINavigationController (reason for second navigation bar).
EDIT:
Function to return detail's Nav Controller:
var detailsNavigationController: UINavigationController? {
return splitViewController?.viewControllers.last as? UINavigationController
}
To access blue call detailsNavController, to access red use navigationController.

How can I embed my navigation controller into my tab bar controller programmatically in Swift Xcode 8.2?

I have been teaching my self how to develop and I got to the point to where I need guidance from experts. I created some of the user interface programmatically using the MVC structure. My question is how can I embed my navigation controller into my tab bar controller so my tab bar controller can be on every screen. I made the tab bar controller in main.storyboard and referenced it in the View controller I named Home Controller.
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabViewController = storyboard.instantiateViewController(withIdentifier: "TabBar")
self.present(tabViewController, animated: true, completion: nil)
The code above is in the view did load function. I was wondering do I need to change up the root view controller in my app delegates?
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
This is in my finished launched func.
Use following lines
var navigationController = UINavigationController(rootViewController: viewController));
tabBarController.viewControllers = [navigationController,firstViewControllersecondViewController, ]
create a separate UITabBarController class and initialize it in AppDelegate like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = MyTabBarController()
window?.makeKeyAndVisible()
return true
}
and the custom tabBarController
import UIKit
class MyTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBar.barTintColor = UIColor.black
self.tabBar.tintColor = UIColor.white
self.tabBar.unselectedItemTintColor = UIColor.white.withAlphaComponent(0.4)
let firstViewController = FirstViewController()
let firstViewTabBarItem = UITabBarItem(title: "First", image: UIImage(named: "calculator"), selectedImage: UIImage(named: "calculator"))
firstViewController.tabBarItem = firstViewTabBarItem
firstViewController.tabBarItem.tag = 0
let historyViewController = HistoricDataViewController()
historyViewController.tabBarItem = UITabBarItem(tabBarSystemItem: .history, tag: 1)
let tabBarList = [calculateViewController, historyViewController]
viewControllers = tabBarList.map{UINavigationController(rootViewController: $0)}
}
}
Hope this example helps.

How to set rootview in tabbar controller and show tabbar in each view controller in swift ios?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.backgroundColor = UIColor.white
let tabBarController = self.window!.rootViewController as! UITabBarController
let tabBar = tabBarController.tabBar as UITabBar
let tabBarItem0 = tabBar.items![0] as! UITabBarItem
let tabBarItem1 = tabBar.items![1] as! UITabBarItem
let tabBarItem2 = tabBar.items![2] as! UITabBarItem
let tabBarItem3 = tabBar.items![3] as! UITabBarItem
tabBar.barTintColor = UIColor(red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0)
tabBarItem0.title = "Home"
tabBarItem1.title = "Search"
tabBarItem2.title = "User"
I am new to swift. I have configured the tab bar controller in appdelegate.Now I need to set the rootview controller here and I need to show the tabbar in all my viewcontrollers that I declare.
This will help you. Try to set navigation inside of tab bar controller. Give tab bar item to navigation controller. Like:
Output is:
When you press button:
You can create tabbarcontroller like below, using Xib
//MARK: didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let tabBarController = UITabBarController()
let tabViewController1 = FirstTabViewController(nibName: "FirstTabViewController", bundle: nil)
let tabViewController2 = SecondViewController(nibName:"SecondViewController", bundle: nil)
tabViewController1.tabBarItem = UITabBarItem(title: "Home", image: UIImage(named: "home_icon"),tag: 1)
tabViewController2.tabBarItem = UITabBarItem(title: "Search",image:UIImage(named: "search_icon") ,tag:2)
tabBarController.viewControllers = [tabViewController1,tabViewController2]
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
As per my understanding, you want to achieve something like this :
UITabBarController --> for each tab there will be a navigation controller whose Root will be a VC having tab bar
So I would suggest you to directly use UITabBarControllers for your each root of navigation controller.
That means your root will be UITabBarController, then for each tab there will be UINavigationController whose first view controller will be again a UITabBarController.
For more understanding see below figure. It's only showing flow for one tab of UITabBarController. Repeat the same for all your other tabs.

Resources