Skip to content

Instantly share code, notes, and snippets.

@max-potapov
Last active February 3, 2022 08:01
Show Gist options
  • Save max-potapov/aba3bb026e9911d091f0c70af4cc13e6 to your computer and use it in GitHub Desktop.
Save max-potapov/aba3bb026e9911d091f0c70af4cc13e6 to your computer and use it in GitHub Desktop.
UITabBarController inside Master View of UISplitViewController
//
// SplitViewController.swift
// Gist
//
// Created by Maxim Potapov on 17/12/2017.
// Copyright © 2017 Maxim Potapov. All rights reserved.
//
import UIKit
protocol MasterViewController {
var collapseDetailViewController: Bool { get set }
}
protocol DetailViewController {}
final class SplitViewController: UISplitViewController {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
detail.topViewController!.navigationItem.leftBarButtonItem = displayModeButtonItem
preferredDisplayMode = UIDevice.current.userInterfaceIdiom == .pad ? .allVisible : .automatic
}
}
extension SplitViewController: UISplitViewControllerDelegate {
private var master: UITabBarController {
return viewControllers.first as! UITabBarController
}
private var detail: UINavigationController {
return viewControllers.last as! UINavigationController
}
func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
guard splitViewController.isCollapsed else { return false }
guard let selected = master.selectedViewController as? UINavigationController else { return false }
let controller: UIViewController
if let navigation = vc as? UINavigationController {
controller = navigation.topViewController!
} else {
controller = vc
}
controller.hidesBottomBarWhenPushed = true
selected.pushViewController(controller, animated: true)
return true
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
guard let topAsDetailController = secondaryAsNavController.topViewController, topAsDetailController is DetailViewController else { return false }
guard let tabBar = primaryViewController as? UITabBarController else { return false }
for controller in tabBar.viewControllers! {
guard let navigation = controller as? UINavigationController else { continue }
guard let master = navigation.topViewController as? MasterViewController, master.collapseDetailViewController == false else { continue }
topAsDetailController.hidesBottomBarWhenPushed = true
navigation.pushViewController(topAsDetailController, animated: false)
return true
}
return false
}
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
guard let selected = master.selectedViewController as? UINavigationController else { return nil }
guard selected.topViewController is DetailViewController else { return nil }
guard let details = selected.popViewController(animated: false) else { return nil }
return UINavigationController(rootViewController: details)
}
}
@AlexChekanov
Copy link

Hi! Really useful code. Thank you. I have the only problem in the expanded mode: I set up my master-detail configuration in the storyboard and I have a "Show detail" segue from my master UITableViewController to my detail UIViewController. When this segue performs, the displayModeButtonItem disappears. Can't find any solution. Thank you in advance for your help.

@AlexChekanov
Copy link

I understood! I shouldn't perform the segue if the splitViewController isn't collapsed. I already have the controller. Sorry )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment