Cannot place UISplitViewController inside UITabBarController - swift

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

Related

how use navigation controller with xib in 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()

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

Programmatically create a navigation view

So I'm trying to create an app but I'm trying to avoid the use of storyboards. Hence just using swift files along with XIB files.
I have worked a little with Navigation controllers before but not enough I guess. So far I have this:
In AppDelegate I have:
let homeVC = HomeViewController()
let rootVC = UINavigationController(rootViewController: homeVC)
window!.rootViewController = rootVC
window!.makeKeyAndVisible()
My view currently is entirely empty, but with the basic "View" screen that comes with creating a new XIB file. I've set the size of that to freeform, and all other things like Top Bar, Status Bar are Inferred.
In my HomeViewController.swift I have:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let nib = UINib(nibName: "HomeView", bundle: nil)
let objects = nib.instantiateWithOwner(self, options: nil)
self.view = objects[0] as! UIView;
print(self.navigationController)
// customize navigation bar
let settingsImage = UIImage(named: "settingsWheelBlack.png")
let settingsNavItem = UIBarButtonItem(image: settingsImage, style: UIBarButtonItemStyle.Plain, target: nil, action: Selector("selector"))
let addStuffItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: nil, action: Selector("selector"))
self.navigationController?.navigationItem.title = "Home"
self.navigationController?.navigationItem.leftBarButtonItem = settingsNavItem
self.navigationController?.navigationItem.rightBarButtonItem = addStuffItem
print(self.navigationController?.navigationBar)
print(self.navigationController?.navigationItem.title)
}
But when I run the application the navigation bar doesn't show up. Here's what I've tried besides what I currently have:
Add a Navigation Bar control to my XIB and connect an IB outlet to it. Also connect the IB outlet to the navigation item that already exists in the navigation bar control. Then set the title, and left and right buttons in that. Didn't work
Set the title and buttons in AppDelegate straight away for the rootVC defined above. Didn't work.
Any ideas what I'm missing?
I solved this after gathering some strength to read through tons of Apple docs. On this page I found this small piece of text:
In a navigation interface, each content view controller in the navigation stack provides a navigation item as the value of its **navigationItem** property. The navigation stack and the navigation item stack are always parallel: for each content view controller on the navigation stack, its navigation item is in the same position in the navigation item stack.
So I left my AppDelegate code as is and changed me viewDidLoad function to:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let nib = UINib(nibName: "EventsHomeView", bundle: nil)
let objects = nib.instantiateWithOwner(self, options: nil)
self.view = objects[0] as! UIView;
print(self.navigationController)
// customize navigation bar
let settingsImage = UIImage(named: "settingsWheelBlack.png")
let settingsNavItem = UIBarButtonItem(image: settingsImage, style: UIBarButtonItemStyle.Plain, target: nil, action: Selector("selector"))
let addStuffItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: nil, action: Selector("selector"))
// Each VC within a navigation controller has it's own navigationItem property that the underlying navigation controller uses to show in the navigationBar
self.navigationItem.title = "Home"
self.navigationItem.leftBarButtonItem = settingsNavItem
self.navigationItem.rightBarButtonItem = addStuffItem
}
And viola!

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.

Howto Size the Modal View programmatically (SWIFT)

I simply want to present a small option dialog over an existing main UIViewController/UIView , so that on an IPad I would see a small Dialog and in the Background I will see the Main View.
I managed to show a UIViewController/UIView in a modal view style as follow:
func showoptions(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("Options") as! UIViewController
controller.modalPresentationStyle = UIModalPresentationStyle.Popover
let popoverPresentationController = controller.popoverPresentationController
// result is an optional (but should not be nil if modalPresentationStyle is popover)
if let _popoverPresentationController = popoverPresentationController {
// set the view from which to pop up
_popoverPresentationController.sourceView = self.view;
//_popoverPresentationController.sourceRect = CGRectMake(60, 100, 500, 500)
//_popoverPresentationController. .setPopoverContentSize(CGSizeMake(550, 600), animated: true)
//_popoverPresentationController.sourceView.sizeToFit();
// present (id iPhone it is a modal automatic full screen)
self.presentViewController(controller, animated: true, completion: nil)
}
}
But I have still some issues:
1. Howto get rid of the arrow shown at the border.
2. Howto size this modal view. It is shown to small and I would like to fit it to the largest controls in the UIControllerView/UIView.
any help ?
Try changing _popoverPresentationController.permittedArrowDirections to empty option set
Change controller.preferredContentSize to match your desired size
I needed something similar and ended up presenting a view controller as a modal with a transparent background over the current context. There I made a smaller opaque UIView with what I wanted.