I'm trying to create UITabBarController programmatically, adding multiple NavigationControllers to it. When UITabBarController contains one NavigationController - everything works as expected (see image)
But when i add multiple NavigationControllers to UITabBarController each screen becomes black (see another image )
The same black screen is shown when switching between tabs 1, 2, 3, 4 and 5.
Here's the code how UITabBarController is created
class TabBarViewController : UITabBarController{
override func viewDidLoad() {
super.viewDidLoad()
let controllers = [HistoryViewController.self, StatsViewController.self, DashboardViewController.self, ExpenseManagerViewController.self, ProfileViewController.self]
var navControllers: [UINavigationController] = []
controllers.forEach{ ctrl in
navControllers.append(getController(from: ctrl))
}
tabBar.tintColor = Color.green
viewControllers = navControllers
}
private func getController<TType: UIViewController>(from type: TType.Type) -> UINavigationController{
let ctrl = TType()
let navCtrl = UINavigationController(rootViewController: ctrl)
let ctrlName = String.init(describing: type.self).replacingOccurrences(of: "ViewController", with: String.empty)
navCtrl.tabBarItem.title = ctrlName
navCtrl.tabBarItem.image = UIImage(named: ctrlName)
navCtrl.navigationBar.topItem?.title = ctrlName
return navCtrl
}
}
Those UIViewControllers are created using "add Cocoa Touch Class" option and have assigned *.xib files with some minimum design (see one more image)
Any help regarding why all screens become black when multiple (2 and more) NavigationControllers added to TabBarController would be highly appreciated.
Thanks
Clearly you forget how to init the UIViewControllers with xib file:
private func getController<TType: UIViewController>(from type: TType.Type) -> UINavigationController{
let ctrl = TType(nibName: String.init(describing: type.self), bundle: nil)
let navCtrl = UINavigationController(rootViewController: ctrl)
First if you come from any screen then dont insert navigationbar in between that viewcontroller and tabbarcontroller and when you jump to tabbarcontroller set as rootview controller and any tab you want to open than place navigation controller in between. means dont open tabbar controller with navigationbar heirarchy but when u want to open controller with tabs then place navigation controller in between.
Related
Sorry, if it is an essential question.
The scheme is the following:
enter image description here
I want the following:
User taps last Tab
User goes to some ViewController (different from ViewController, actually connected with last Tab)
How to do this (without using segue)?
Thanks a lot in advance!
You can go with instantiateViewController with push when load your tab and push one viewController to another like below:
let next = self.storyboard?.instantiateViewController(withIdentifier: "nextVC")as! nextVC
self.navigationController?.pushViewController(next, animated: true)
You can assign ViewController in you UITabBarController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// create view controllers from storyboard
// Make sure you set Storyboard ID for both the viewcontrollers in
// Interface Builder -> Identitiy Inspector -> Storyboard ID
let clockViewController = storyboard.instantiateViewControllerWithIdentifier("ClockViewController")
let stopWatchViewController = storyboard.instantiateViewControllerWithIdentifier("StopWatchViewController")
// Set up the Tab Bar Controller to have two tabs
let tabBarController = UITabBarController()
tabBarController.viewControllers = [clockViewController, stopWatchViewController]
// Make the Tab Bar Controller the root view controller
window?.rootViewController = tabBarController
I need to have two different tabs for one UIViewController.
I implement UITabBarController programmatically.
Code below works like show me two different tabs, but when I select firstVC it has black screen, secondVC is good.
How can I use two different tabs for same ViewConetroller?
class VPTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let myWebView = WebKitViewController.storyboardInstance()
let mainVC = MainViewController.storyboardInstance()
mainVC?.tabBarItem.title = "Search"
mainVC?.tabBarItem.image = UIImage(named:"search")
let firstVC = myWebView
firstVC?.source = "first"
let accountNavigationVC = UINavigationController(rootViewController: firstVC!)
accountNavigationVC.tabBarItem.title = "First"
accountNavigationVC.tabBarItem.image = UIImage(named:"first")
let secondVC = myWebView
secondVC?.source = "second"
let myTripsNavigationVC = UINavigationController(rootViewController: secondVC!)
myTripsNavigationVC.tabBarItem.title = "Second"
myTripsNavigationVC.tabBarItem.image = UIImage(named:"Second")
let viewControllerList = [ mainVC, firstVC, secondVC ]
viewControllers = viewControllerList as? [UIViewController]
}
}
I guess you can hack it by creating two wrapper view controllers, that would contain in the view nothing else, just the myWebView's view that you want to have on both tabs. Now create two instances of this wrapper, that would both include the same myWebView as a subview.
Now you have to remember that the same view cannot be a subview of two different views (it can have only one superview). By adding the myWebView.view as a subview to a wrapper removes it from its previous superview. Therefore, you have to listen to tab changes in order to re-add it when a wrapper gets presented (each time a wrapper is presented, you have to add myWebView as a subview to the presented wrapper).
I created a custom search bar and embedding it in the navigation bar, it appears but after I push another view controller, the search bar does not get replaced with the title of the pushed view controller. The search bar stays persistent throughout all views, instead of getting replaced with a title. Perfect example is Instagram search tab, you search for a person and click on the cell, their profile is pushed and the search bar is replaced with the custom title, back button, etc.
First VC
self.customSearchBar.tag = 4
self.navigationController?.view.addSubview(customSearchBar)
Second VC
if let nav: UINavigationController = self.navigationController {
if let searchBar = nav.view.viewWithTag(4) {
searchBar.removeFromSuperview()
}
}
You shouldn't place the searchbar inside the navigationcontroller view as this view is the same instance on all pushed viewcontrollers.
Add the searchbar to the the depending view controllers ui.
To add a searchbar on navigationBar, this is the way.
self.navigationController?.navigationBar.addSubview(customSearchBar)
To remove it when you push it to other viewController. Write the following code in the secondVC that is pushed inside it's viewDidLoad() function. Also, set the tag of customSearchBar to any number (TAG)
if let nav: UINavigationController = self.navigationController {
let bar: UINavigationBar = nav.navigationBar
if let searchBar = bar.viewWithTag(TAG) {
searchBar.removeFromSuperview()
}
}
In the question, the customSearchBar is added to self.navigationController.view. To remove it, you can do the following:
if let nav: UINavigationController = self.navigationController {
if let searchBar = nav.view.viewWithTag(TAG) {
searchBar.removeFromSuperview()
}
}
Edit:
Adding and removing a UIViewController's view as a subview of other UIViewController
// for adding
let viewController: ViewController = ViewController()
self.addChildViewController(viewController)
self.view.addSubview(viewController.view)
viewController.view.bounds = self.view.bounds // better to use autolayout here
viewController.didMove(toParentViewController: self)
// for removing
if let vc = self.childViewControllers.last {
vc.willMove(toParentViewController: nil)
vc.view.removeFromSuperview()
vc.removeFromParentViewController()
}
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've just created a tab UIViewController in Swift, brand new, no code.
I wanted to know how I could change which tab the app starts on. For example, it has view 1 and view 2. At the bottom it has two tabs, tab 1 and tab 2. How could I get it to where the tab and page it starts on is tab 2, view 2. Instead of always opening and starting on the first tab. Thank you for the help!
i think its natural that the UITabViewController shows the first UIViewController.
edit:
The best solution is to subclass the UITabBarController and to change the selected index in it's viedDidLoad() Delegate:
Create a subclass file of UITabBarController (File -> New -> File -> Cocoa Touch Class)
Set this new file as the Class in the UITabBarController of your Storyboard.
Add in the new file:
override func viewDidLoad() {
super.viewDidLoad()
tabBarController.selectedIndex = 1
// or: tabBarController.selectedViewController = myViewController
}
Here's a possible solution. In your viewWillAppear method.
override func viewWillAppear() {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("Enter your tabBar storyboard ID here") as! UITabBarController
vc.selectedIndex = 0
self.presentViewController(vc, animated: true, completion: nil)
}
The selectedIndex 0 is the first tabBar. You can change this to whichever tabbar you want to open
Set a storyboard ID in main.storyboard identity ID