how use navigation controller with xib in Swift - swift

I have a query which is quite intriguing to me, it happens that I am learning Swift, it seems to me fantatisc the tools that xcode provides make the job a lot easier, but based on my experience in Android projects as a minimum it is recommended to use MVC to maintain the order of the project, same try to swift for which they recommended me to use xib files, it can also be used to work in groups. Until there is everything fantastic but when I tried to implement it I find it too complicated, for which I preferred to use storyboards but the use of libraries and other files make that when loading my storyboard file I delayed too much which is because it is loaded with enough ViewController. Added to this, using the NavigationController in storyboards is easy, it makes navigating a lot easier. My problem is how could I do this with xib files? In a moment I try to do it, but my ViewController loaded vertically and without the navigation bar and I have no idea how to develop it.
By code to load a ViewController is this way.
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let menuVC = Storyboard.instantiateViewController(withIdentifier: "MenuSelectedViewController") as! MenuSelectedViewController
self.navigationController?.pushViewController(menuVC, animated: true)
And by interface builder with segue
So how can I develop this navigation bar with xib files and my TabBarController ?

You just need UINavigationController(rootViewController: yourViewController)
Here is an example using this
let yourViewController = DiscoverViewController(nibName: "yourViewController", bundle: nil)
yourViewController.tabBarItem.image = UIImage(named: "imageName")
let navigationController = UINavigationController(rootViewController: yourViewController)
// TabBarController
let tabbarController = UITabBarController()
tabbarController.tabBar.tintColor = ThemeColor
tabbarController.tabBar.barTintColor = .white
tabbarController.viewControllers = [navigationController] //add your other controllers here as needed
// Make it root or what ever you want here
self.window?.rootViewController = tabbarController
self.window?.makeKeyAndVisible()

Related

Cannot place UISplitViewController inside UITabBarController

I've read all the other responses to this, and they all seems really old and don't seem to work.
I'm trying to create an application with a UITabBar, and have on of those tabs be a UISplitViewController.
The setup is fairly simple:
let redViewController = UIViewController()
redViewController.view.backgroundColor = .red
let blueViewController = UIViewController()
blueViewController.view.backgroundColor = .blue
let splitViewController = UISplitViewController(style: .doubleColumn)
splitViewController.setViewController(redViewController, for: .primary)
splitViewController.setViewController(blueViewController, for: .secondary)
let tabBarController = UITabBarController()
tabBarController.setViewControllers([splitViewController], animated: false)
window?.rootViewController = tabBarController
What I'm expecting
What I get
Secondary
Primary
UISplitViewController changed quite a bit in iOS 14 with the introduction of column-style layouts. Column-style split view controllers cannot be embedded in tab bar controllers, but classic style ones can. You create a classic style split view controller by using any initialiser except for init(style:).
For example:
let red: UIViewController = ...
let blue: UIViewController = ...
// Note that the pre-iOS 14 initialiser is being used
let splitViewController = UISplitViewController(nibName: nil, bundle: nil)
splitViewController.viewControllers = [red, blue]
splitViewController.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 0)
let tabBarController = UITabBarController(nibName: nil, bundle: nil)
tabBarController.viewControllers = [splitViewController]
Note that you can't use any of the new API introduced in iOS 14 with classic style split views (eg the triple column layout, split behaviour). If you want to use this new API you'll have to use a sidebar instead of a tab bar.
I reported this problem in Feedback Assistant but apparently it's working as intended. I guess this is Apple's way of favouring sidebar based navigation over tab bar navigation in iPad apps.
you can see from the storyboard,
Apple seems not to agree

How to present unique UITabBarControllers in Swift

I'm working on a project that has two different UITabBarControllers to represent two different states of the app. I can set the first UITabBarController once a user logs in and present the second when a button is pressed. However, I'm getting odd behavior when navigating within the second UITabBarController.
This is how I set the main tab bar.
let mainTabBar = MainTabBarController()
let mainMode = UINavigationController(rootViewController: mainTabBar)
UIApplication.shared.keyWindow?.rootViewController = mainMode
I use an identical method to navigate to the second tab bar.
let secondaryTabBar = SecondaryTabBarController()
let hiddenMode = UINavigationController(rootViewController: secondaryTabBar)
UIApplication.shared.keyWindow?.rootViewController = hiddenMode
However, when using the secondary UITabBarController, I see views from the main UITabBarController when navigating to an AVCaptureSession. More specifically, I see the last view (from which the secondaryTabBar is set) from the mainTabBar under the modal presentation of the capture session. Here's the problem point:
let captureSession = CameraViewController()
navigationController?.present(captureSession, animated: true, completion: nil)
I changed the modalPresentationStyle of the CameraViewController to .overCurrentContext and that solved the issue. Got it from here: Transparent background for modally presented viewcontroller

Swift -injecting vars in ViewControllers

I am proudly new to iOS developing and I am trying to build my first app. I am doing a course on an online platform which does the following in the
AppDelegate -> application didFinishLaunchingWithOptions:
let navigationController = window?.rootViewController as! UINavigationController
let notebooksListViewController = navigationController.topViewController as! NotebooksListViewController
notebooksListViewController.dataController = dataController
This app has a Navigation controller which begins with an UIViewController.
I have 2 questions here, first is why this works, I mean, I am in AppDelegate, so the NotebooksListViewController (first view of the app) is not instantiated yet (I think), so why I am able to inject a variable in it?
On the other hand, the second question, is how can I do this in a different scene? I have a TabBarViewController as first scene, and the first tab is a UITableViewController and I want to inject the same way my dataController var, how can I accomplish this? I could not get to do it, neither understand it.
Thanks in advance.
It works, because of some Xcode magic:
In your Target Setting, General tab, the Main Interface entry specifies the name of the Storyboard to be loaded automatically when your app starts up:
In the storyboard, the Initial View Controller then will be instantiated. It seems like this is an UINavigationController.
Since this is done automatically, it just works - until you want to do something special :-)
If you want to start up with a different scene - maybe from a different view controller - you could just change either the Main Interface to another storyboard, the Initial View Controller (inside the storyboard) or both.
Or, you could just start up by yourself, by leaving the Main Interface empty and create your own view controller inside the app delegate (didFinishLaunchingWithOptions), something like
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let tabVC = mainStoryboard.instantiateViewControllerWithIdentifier("TabCtrl") as? UITabBarController {
self.window?.rootViewController = tabVC
// Access the subcontrollers, or create them
// Initialize their values
// tabVC.viewControllers[0].data = ...
} else {
// Ooops
}
self.window?.makeKeyAndVisible()
Answer to your first question
as the method name is self explanatory didFinishLaunchingWithOptions means your application is didfinish with launching with options and its about to enter in foreground so here application need to set rootViewController so in this method controller you want to set as view controller is initiated thats why you can inject variable in it
answer to second question
let navigationController = window?.rootViewController as! UITabbarController
let VC = navigationController.childViewController
//Now Using VC you can access all you controller of tabbar controller
let notebooksListViewController = navigationController.topViewController as!
NotebooksListViewController
notebooksListViewController.dataController = dataController
now as shown above you can use VC to access you view controllers
but be careful here because VC return viewcontroller array so you need make checks for perticular VC you want to access

Xcode 8, adding UIButtons to NavigationBar for non initial view controllers

I'm trying to achieve what I think would be a simple task, but despite similar posts on here being answered, the solution eludes me....
I'm using Main.storyboard in Xcode 8/swift 3 to create an application with the initial ViewController being a UINavigationController. I then want to push to UITabBarController which has two view controllers which it holds a relationship with:
override func viewDidLoad() {
super.viewDidLoad()
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let vc = mainStoryboard.instantiateViewController(withIdentifier: "test") as? UITabBarController {
self.navigationController?.pushViewController(vc, animated: true)
}
}
When launching the app, the initial ViewController successfully 'pushes' to the TabBarController/it's ViewControllers (image below). The issue I'm having is after adding navigation items/buttons in the TabBarController ViewControllers (either in Storyboard or programmatically) the buttons / nav items never show.
Storyboard setup
Simulator screenshot
I have seen a few posts such as the below links and have followed the suggested steps verbatim, but nothing has solved the problem. Any help would be greatly appreciated!
Adding buttons to navigation controllers
How to add buttons to navigation controller visible after segueing?
It's does not show, because your TabBarController also have his own UINavigationBar. ViewControllers are inside TabBarController
you can create custom TabBarController and handle tabs actions
Try this code:
class TabBarController: UITabBarController {
override var selectedViewController: UIViewController? {
didSet {
switch self.selectedViewController {
case self.selectedViewController is FirstViewController:
self.navigationItem.rightBarButtonItem = self.firstButton
case self.selectedViewController is SecondViewControlller:
self.navigationItem.rightBarButtonItem = self.secondButton
default:
break
}
}
}
}

Can it be non rootviewcontroller?

I'm implementing a drawer layout design in an app.
But my app starts with a small screen with an animated logo (simple HTML5 animation), then a login screen (g+ and Facebook), then the main screen where I'm implementing the MMDrawerController.
The question is in my AppDelegate:
window?.rootViewController = centerContainer
window?.makeKeyAndVisible()
So the app start in this screen. Is it possible to not make rootviewcontroller the center container and still using MMDrawerController?
I need to add MMDrawerController to my third viewcontroller in my app
But, in order to MMDrawerController to work, it requires to be the rootViewController
I allready tried to add to my first ViewController an Empty MMDrawerLayout but, then, the third controller no longer works
//global var
var centerContainer : MMDrawerController?
// then the appdelegate
let rootViewController = self.window!.rootViewController
let mainStoryBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let centerViewController = mainStoryBoard.instantiateViewControllerWithIdentifier("GaleriaPeliculas")
let leftViewController = mainStoryBoard.instantiateViewControllerWithIdentifier("LeftSideViewController")
let leftSideNav = UINavigationController(rootViewController: leftViewController)
let centerSideNav = UINavigationController(rootViewController: centerViewController)
//And here is the problem,
window?.rootViewController = centerContainer //how can it work without this line??
window?.makeKeyAndVisible()
Is it possible to not make rootviewcontroller the center container and still using MMDrawerController?
No. You need to keep MMDrawerController as the rootViewController if you still want to make use of the left/right drawers. It's no different than a UITabBarController in the sense that it contains multiple view controllers to be conditionally displayed.