I created an application in which I have a UISpliеViewController, also the master section has a tabbar. In the tabbar I have three controllers. When I click on the second item tabbar in portrait orientation, I have a controller called News. But when I'm in the horizontal position, I want the master section to open the controller that is on the tabbar item1, and the detail must have the News tab.
I read and think that I need to use:
func primaryViewController (forExpanding splitViewController: UISplitViewController) -> UIViewController? or
func splitViewController (_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, on primaryViewController: UIViewController) -> Pain
, but I do not understand how to organize it
Related
I have implemented a UISplitViewController and all works fine. What I want to do is on iPhone devices only show the detailView not the masterView as the first view controller. I realise I can create a segue from the master view to the detail view in the masters viewDidLoad method however this feels a bit hacky to me. Maybe this is the only way to achieve what I want?
I have looked at the documentation for the UISplitViewControllerDelegate particularly this function however I don't feel I grasped what this actually is doing. I have also set the UISplitViewController as the delegate and set allVisible and tried all the other options in the viewDidLoad of my SplitViewController sub class
self.delegate = self
self.preferredDisplayMode = .allVisible
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
return true
}
If it helps the detailViewController heirachy in the storyboard is SplitViewController > UINavigationController > myDetailViewController
What you need to do is to use the splitviewcontroller delegate function
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool
In there you can push your second controller into your first navigation controller and return true. Returning true means that you're gonna handle the transition. e.g.
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
if let detailViewController = secondaryViewController as? YourSecondViewController, let primaryNV = primaryViewController as? UINavigationController {
primaryNV.pushViewController(detailViewController, animated: false)
returns true // I handle it myself.
}
return false // let the iOS handles it.
}
If you need more clarification, please let me know. I'll try to explain it better. cheers!.
I’m working on an app that is misbehaving. The app has a splitViewController which, on first launch, fires the :
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool
function. However after rotating to landscape and back to portrait, it never fires again (and subsequently is showing my detail view instead of the master view which is not what I want). I’ve set the splitViewController.delegate to self… Can anyone give me some clues on what I should look more closely at to debug this?
Ok found out my own answer. In this case in our detailViewController in viewDidLoad() we had assigned splitViewController?.delegate = self (why, I'm not sure at this point - the code is somewhat old). Removing this made the collapseSecondary function fire off as expected. Hope this helps someone.
In my app I have a split view controller in a tab bar controller, and the master view controller is embedded inside a navigation controller. Initially the detail view controller is just a blank view controller. Now upon separating from 1 column to 2, the view controller in the primary position is strangely no longer extended under the top and bottom bars. The bars are translucent so you should be able to see the red in the nav and tab bars. I’ve narrowed the problem down to splitViewController(_:separateSecondaryFrom:) which I use to embed the detail in a navigation controller. I don’t see why this is causing this behavior in the primary though. What is incorrect with my implementation of this method?
Red appears in the bars as expected in the collapsed interface:
Upon expanding to two columns the red no longer appears in the bars:
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
//in the case where it's separating into two, we want to embed the detail in a navigation controller
let primaryNavController = primaryViewController as! UINavigationController
let detailController: UIViewController
if primaryNavController.viewControllers.count > 1 {
detailController = primaryNavController.viewControllers[1]
} else {
detailController = ViewController()
}
return UINavigationController(rootViewController: detailController)
}
I've uploaded a sample project here.
There's probably a hiccup in drawing the translucency and blur of the view beneath the bars. May be due to some drawing and caching optimization in the framework but when I triggered the bar hidden and show event on navigation bar, it was fine.
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
//in the case where it's separating into two, we want to embed the detail in a navigation controller
let primaryNavController = primaryViewController as! UINavigationController
let detailController: UIViewController
if primaryNavController.viewControllers.count > 1 {
detailController = primaryNavController.viewControllers[1]
} else {
detailController = ViewController()
}
//Fake trigger to force bars to draw blur translucency
let navigationNew = UINavigationController(rootViewController: detailController)
navigationNew.setNavigationBarHidden(true, animated: false)
navigationNew.setNavigationBarHidden(false, animated: false)
return navigationNew
}
Let me know if it works for you.
iOS 10/Swift:
Using SplitViewController on an iPhone the user sees the detail view when the app loads (whether in portrait or landscape both have compact width). How can you change this to load the master view on startup?
Note that when you load in a Regular Width view (ie: iPhone 6s Plus landscape) we want the Split View to continue to be shown (and not master).
You should use method
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool
which provided by UISplitViewControllerDelegate
You can define a custom UISplitViewController and assign it to your split view in the storyboard:
import UIKit
class MainSplitViewController: UISplitViewController, UISplitViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
return true
}
}
I had a UISplitViewController with the following layout, consisting of a single master and detail view controller.
This worked fine for a basic split view with single views, but I needed to support multiple segues from the UITableViewController (Master View) and not load the detail views until data is passed; or else the app will crash because of optional errors.
I tried by having a set up like so;
This loads a blank ViewController as the detail view when the UISplitViewController loads, and when a row is selected the I have a detail segue to the other view controllers, which should appear as a detail view in the UISplitViewController.
This unfortunately does not work exactly, all the data is passed and loaded without crashes but the detail segues actually load the view controllers within the master view window of the split view not the detail view.
Kind of like this,
How can I have multiple detail view controllers which are not loaded until initiating a segue from the master view UITableViewController and open in the detail window ?
Here's the code from the MasterViewController
override func viewDidLoad() {
super.viewDidLoad()
self.splitViewController!.delegate = self;
self.splitViewController!.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
self.extendedLayoutIncludesOpaqueBars = true
}
func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController: UIViewController, ontoPrimaryViewController primaryViewController: UIViewController) -> Bool {
return true
}
If the segues were already there then try removing the segues from the master view to the other detail views and recreating them using a detail segue.