Presenting a custom tab view controller but getting a black screen - ios

My goal is to display a tab view controller that manages multiple tabs that consist of navigation controllers containing view controllers.
I set the tab view controller BaseTabBarController as window my root view controller in AppDelegate. My custom tab view controller looks like this:
class BaseTabBarController: ESTabBarController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
let v1 = BaseNavigationController(rootViewController: SubscriptionsController())
let v2 = BaseNavigationController(rootViewController: SubscriptionsController())
v1.tabBarItem = ESTabBarItem(title: "Home", image: #imageLiteral(resourceName: "tab_bar_home"), selectedImage: #imageLiteral(resourceName: "tab_bar_home"))
v2.tabBarItem = ESTabBarItem(title: "Home", image: #imageLiteral(resourceName: "tab_bar_home"), selectedImage: #imageLiteral(resourceName: "tab_bar_home"))
self.viewControllers = [v1, v2]
self.hidesBottomBarWhenPushed = true
}
}
My custom navigation controller class is an empty subclass of a navigation controller.
The problem is that the app displays a tab bar for a fraction of a second, and immediately turns into a black screen (console message: "Presenting view controllers on detached view controllers is discouraged"). What did I do wrong?

there has got to be something wrong with some other parts of your code. when i take your code and use it like this everything works as expected:
class BaseTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
let v1 = UINavigationController(rootViewController: UIViewController())
let v2 = UINavigationController(rootViewController: UIViewController())
v1.tabBarItem = UITabBarItem(title: "Home", image: nil, selectedImage: nil)
v2.tabBarItem = UITabBarItem(title: "Home", image: nil, selectedImage: nil)
self.viewControllers = [v1, v2]
self.hidesBottomBarWhenPushed = true
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = BaseTabBarController()
window?.makeKeyAndVisible()
return true
}

Related

Why navigation controller is nil even though I push it

I have a LoginViewController and want to push MainTabBarController
So, I do this
let controller = MainTabBarController()
navigationController?.pushViewController(controller, animated: true)
LoginViewController has a navigation controller but MainTabBarController doesn't for some reasons.
I have two questions, if my flow is LoginViewController -> MainTabBarController -> Other Controllers embedded in MainTabBarController, and I want to log out, how do I get to the LoginViewController without memory leaks? I was thinking about something like popToRootViewController but not sure if it would work.
This is how I'm creating other controllers in MainTabBarController
private func createNewViewController(viewController: UIViewController, title: String, imageName: String) -> UIViewController {
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.tabBarItem = UITabBarItem(title: title, image: UIImage(systemName: imageName), selectedImage: nil)
navigationController?.view.backgroundColor = .white
viewController.navigationItem.title = title
return viewController
}
But it doesn't really work since navigationController is nil. I don't use storyboards at all though.
EDIT: Apparently embedding a UITabBarController inside a UINavigationController is not supported.
Try this design. When LoginVC appears it checks if user is logged in and re-directs to MainVC. This is just a skelton, add more details as you go forward:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
window = UIWindow()
window?.makeKeyAndVisible()
window?.rootViewController = LoginVC()
return true
}
}
class LoginVC: UIViewController {
var isUserLoggedIn = true
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
view.backgroundColor = .red
if isUserLoggedIn {
present(MainVC(), animated: true)
}
}
}
class MainVC: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
modalPresentationStyle = .fullScreen
let firstVC = UIViewController()
firstVC.tabBarItem = UITabBarItem(title: "firstVC", image: nil, selectedImage: nil)
let secondVC = UIViewController()
secondVC.tabBarItem = UITabBarItem(title: "secondVC", image: nil, selectedImage: nil)
viewControllers = [firstVC, secondVC]
}
}

How to embed a view in a navigation controller programmatically?

I have 3 view controllers in a UITabBarController. In only one view controller I would like to place it in a navigation controller. What is the proper way of doing this so that only one view controller has a Navigation Controller? I would like aController to be in a navigation controller.
import UIKit
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let mController = MViewController()
mpController.tabBarItem = UITabBarItem(title: "view1", image: UIImage(named: "viewoneimage"), tag: 0)
let inputController = InputViewController()
inputController.tabBarItem = UITabBarItem(title: "Input", image: UIImage(named: "plus"), tag: 1)
let aController = ATableViewController()
aController.tabBarItem = UITabBarItem(title: "custom", image: UIImage(named: "person.fill"), tag: 2)
let navController = UINavigationController()
// aController.navigationController = navController
viewControllers = [mController, inputController, aController, navController]
// Do any additional setup after loading the view.
}
}
You must embend your UIViewController inside the Navigation Controllers and initialize your tab menu with your Navigation Controllers.
Also for each tab you will have different Navigation Controller
Your code should look like that.
import UIKit
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let mController = MViewController()
mpController.tabBarItem = UITabBarItem(title: "view1", image: UIImage(named: "viewoneimage"), tag: 0)
let inputController = InputViewController()
inputController.tabBarItem = UITabBarItem(title: "Input", image: UIImage(named: "plus"), tag: 1)
let aController = ATableViewController()
aController.tabBarItem = UITabBarItem(title: "custom", image: UIImage(named: "person.fill"), tag: 2)
let navMController = UINavigationController(rootViewController: mpController)
let navInputController = UINavigationController(rootViewController: inputController)
let navaController = UINavigationController(rootViewController: aController)
viewControllers = [navMController, navInputController, navaController]
}
}

Embed custom tab bar controller after loginVC programmatically

I am working without Storyboards.
After the successful login, I'd like to add a tabBar into my viewControllers.
I created another viewController called tabBar controller with the code:
class TabBarController: UITabBarController,UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
// Create Tab one
let tabOne = Home()
let tabOneBarItem = UITabBarItem(title: "Collection", image: #imageLiteral(resourceName: "matchTabIcon"), selectedImage: #imageLiteral(resourceName: "matchTabIconSelected"))
tabOne.tabBarItem = tabOneBarItem
// Create Tab two
let tabTwo = ScoutingVC()
let tabTwoBarItem2 = UITabBarItem(title: "Scouting", image: #imageLiteral(resourceName: "scouting"), selectedImage:#imageLiteral(resourceName: "scoutingSelected"))
tabTwo.tabBarItem = tabTwoBarItem2
self.viewControllers = [tabOne, tabTwo]
}
// UITabBarControllerDelegate method
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
print("Selected \(viewController.title!)")
}
}
What is the correct way to add this to all of my VCs?
I tried
self.vc.addSubView(tabBarController)
and also to create a func() in the first VC (index: 0), but either the tabBar is not there, or if there, doesn't switch between viewControllers.
func showTabBarController() {
// Create Tab one
let home = Home()
let homeTabBarItem = UITabBarItem(title: "Collection", image: #imageLiteral(resourceName: "matchTabIcon"), selectedImage: #imageLiteral(resourceName: "matchTabIconSelected"))
home.tabBarItem = homeTabBarItem
let navHome = UINavigationController.init(rootViewController: home)
// Create Tab two
let scouting = ScoutingVC()
let scoutingTabBarItem = UITabBarItem(title: "Scouting", image: #imageLiteral(resourceName: "scouting"), selectedImage: #imageLiteral(resourceName: "scoutingSelected"))
scouting.tabBarItem = scoutingTabBarItem
let navScouting = UINavigationController.init(rootViewController: scouting)
//showTabBar
tabBarCnt.viewControllers = [navHome, navScouting]
self.view.addSubview(tabBarCnt.tabBar)
}
Instead of using self.vc.addSubView(tabBarController) use present(TabBarController(), animated: false, completion: nil)

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 navigate from one view to another without using NavigationController?

I want to call the UITabBarController after signing in from a UIViewController
I use the pushViewController but it doesn't work.
Here's my code
let dashboarController = DashboardTabBarController()
self.navigationController?.pushViewController(dashboarController, animated: false)
self.dismiss(animated: true, completion: nil)
This is my code in DashboardController
DashboardTabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.view.backgroundColor = UIColor.white
print("test")
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let tabOne = MerchantTableViewController()
let tabOneBarItem = UITabBarItem(title: "Merchant", image: UIImage(named: "icon_merchant"), selectedImage: UIImage(named: "icon_merchant"))
tabOne.tabBarItem = tabOneBarItem
let tabTwo = RewardsViewController()
let tabTwoBarItem2 = UITabBarItem(title: "Rewards", image: UIImage(named: "icon_reward"), selectedImage: UIImage(named: "icon_reward"))
tabTwo.tabBarItem = tabTwoBarItem2
let tabThree = ViewController()
let tabTwoBarItem3 = UITabBarItem(title: "Promos", image: UIImage(named: "icon_promos"), selectedImage: UIImage(named: "icon_promos"))
tabThree.tabBarItem = tabTwoBarItem3
let tabFour = MerchantTableViewController()
let tabTwoBarItem4 = UITabBarItem(title: "Transactions", image: UIImage(named: "icon_card"), selectedImage: UIImage(named: "icon_card"))
tabFour.tabBarItem = tabTwoBarItem4
let tabFive = ProfileViewController()
let tabTwoBarItem5 = UITabBarItem(title: "Profile", image: UIImage(named: "icon_profile"), selectedImage: UIImage(named: "icon_profile"))
tabFive.tabBarItem = tabTwoBarItem5
self.viewControllers = [tabOne, tabTwo, tabThree, tabFour, tabFive]
}
}
I'm a newbie in iOS development. Thanks
Apple doc says : A navigation controller object manages the currently displayed screens using the navigation stack, which is represented by an array of view controllers. The first view controller in the array is the root view controller. The last view controller in the array is the view controller currently being displayed. You add and remove view controllers from the stack using segues or using the methods of this class.
So now , if you don't wanted to you use UINavigationController and add the UIViewController, follow below methods:
Present ViewController
Add as a Child VC
You should have the view controller from which you are navigating is in the navigation. If it is not, then create a navigation view controller's object with root having you source view controller as root view controller.
If you don't want to use navigation controller then you can use PresentViewController method to present view controller.

Resources