Search code examples
iosswiftuinavigationbaruisplitviewcontroller

UISplitView's MasterViewController and Navigation Issue


I am updating my existing app to include a SplitView for iPads.

I have it working with a UITabBar, but am having an issue with my masterViewController as it is generating a "duplicate" navigation bar that is covering my existing navigation items on all masterViewControllers (tabs), including searchBar on the search tab.

The code I have is:

AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{

    let splitViewController = self.window!.rootViewController as! UISplitViewController
    splitViewController.delegate = self
    splitViewController.preferredPrimaryColumnWidthFraction = 0.33
    splitViewController.minimumPrimaryColumnWidth = 375
    splitViewController.preferredDisplayMode = .allVisible

    return true
}

func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
    return true
}

The reason for having this in the AppDelegate is I saw an example where placing it hear will allow me not to require the code in each of the different Master Views (each tab). Have yet to test this as still working on the first master view.

Master View

override func viewDidLoad()

{

    self.extendedLayoutIncludesOpaqueBars = true

    self.navigationItem.hidesBackButton = true

    // 3D Touch
    if traitCollection.forceTouchCapability == .available {
        registerForPreviewing(with: self as UIViewControllerPreviewingDelegate, sourceView: view)
        ThreeDTouch = true
    }

    self.addSwitchVewButtonToNavigationBar()
    self.addCategoryButtonToNavigationBar()

}

func addSwitchVewButtonToNavigationBar() {
    let switchButton = UIButton(type: UIButtonType.custom)

    let editImage = UIImage(named: "CollectionButton")?.withRenderingMode(.alwaysTemplate)
    switchButton.setImage(editImage, for: .normal)
    switchButton.addTarget(self, action: #selector(SpeciesViewController.onSwitchView), for: UIControlEvents.touchUpInside)
    let switchButtonFinal = UIBarButtonItem(customView:switchButton)

    self.navigationItem.rightBarButtonItem = switchButtonFinal

}

@IBAction func onSwitchView(_ sender: UIBarButtonItem)
{
    AppDelegate.getAppState().isListViewSelected = false

    let speciesColletion = storyboard?.instantiateViewController(withIdentifier: Resource.SpeciesCollectionStoryboard) as! SpeciesCollectionViewController
    self.navigationController?.viewControllers = [speciesColletion]
}

Originally, the onSwitchViewButton was embedded using the IB, but did not work. This is the same system used for the addFavorite on the Detail View.

enter image description here

enter image description here


Solution

  • The problem that you addressing wrong UINavigation controller. I assume before splitting both master and SpeciesViewController existed in same navigation environment, and use same navigation controller. But in split view they don't. Your detail controller is actually UINavigation controller you are looking for, that had to control all navigation, and had to have buttons you need. You can get it from master as:

    guard let split = splitViewController, let navController = split.viewControllers.last as? UINavigationController else { return }
    

    And make sure that you split controller not embedded into another UINavigationController (reason for second navigation bar).

    EDIT: Function to return detail's Nav Controller:

    var detailsNavigationController: UINavigationController? {
        return splitViewController?.viewControllers.last as? UINavigationController
    }
    

    Storyboard Split To access blue call detailsNavController, to access red use navigationController.