首先我要说的是,Apple 建议 SpiltVC 以 root 身份开始。我遇到的问题是,如果使用 TabBarVC 作为 root,您必须将其放在 containerView 中,然后将 containerView 作为 root 到作为 SplitVC 的根的 NavVC。
SplitVC > NavVC > ContainerVC > TabBarVC //this wasn't working out
我决定使用 TabBarVC 作为 root 并为每个 Tab 添加一个单独的 SplitVC。如果您查看下图的左侧,这就是 Apple 的 MasterDetailApp 启动时的外观。场景的右侧是我使用的布局。
在图像的右侧,我有一个 TabBar 作为根,每个选项卡都有一个 SplitVC,每个 SplitVc 都有它自己的 NavVC,它本身有它自己的 TableVC 作为它的根:
____SplitVC -- NavVC -- TableVC //this would be tab 0 and where we will focus
/
/
TabBarVC //all the other color vcs I want to get to from the TableVC in tab 0
\
\____SplitVC -- NavVC -- TableVC
请注意,我没有使用的图像右侧包含一个 DetailNavigationController,就像 MasterDetailApp 中包含的一样。
我将只专注于从 TabBar 的第一个选项卡推送 vcs,因为您将对 TabBar 的第二个选项卡使用相同的方法。
要从 appDelegate 的 didFinishLaunching 开始,您只需将要首先登陆的选项卡添加为 selectedIndex:
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//I subclassed the TabBarVC with the name TabBarController
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarVC: TabBarController = mainStoryboard.instantiateViewController(withIdentifier: "TabBarController") as! TabBarController
tabBarController.selectedIndex = 0
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
仅供参考,这里是选项卡 0 的 vcs 的流程和名称:
TabBarContoller > TabZeroSplitVC > TabZeroNavVC > SettingsVC
以这种方式启动将为我提供 SettingsVC,它在 iPad 上将在分屏模式下位于左侧(主侧)。您还必须符合 UISplitViewControllerDelegate 并在 viewDidLoad 中创建它,以便它显示分屏,左侧是主视图,右侧是细节。
SettingsVC: UIViewController, UISplitViewControllerDelegate{
@IBOutlet weak fileprivate var tableView: UITableView!
var colors = ["RedVC", "GreenVC", "BlueVC", "PinkVC"]
override func viewDidLoad() {
super.viewDidLoad()
splitViewController?.delegate = self
//this keeps it in splitScreen mode
splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.allVisible
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.colors.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ColorsCell", for: indexPath) as! ColorsCell
cell.titleLabel?.text = self.colors[indexPath.row]
return cell
}
由于我没有在 Storyboard 中包含 DetailNavigationController,因此屏幕右侧(详细信息侧)将为空白。因此,在启动时,您会看到如下所示的屏幕:
这个想法是首先以编程方式添加 NavVC,然后以编程方式添加 WhiteVC 作为它的根。这样,WhiteVC 最初将显示在屏幕的右侧。关键是使用 splitVCshowDetailViewController(vc: UIViewController, sender: Any?)
以编程方式显示它。顺便说一句,将 nav 添加为类变量很重要,因为我们将使用它来显示其他颜色 vcs。
SettingsVC: UIViewController, UISplitViewControllerDelegate{
@IBOutlet weak fileprivate var tableView: UITableView!
var colors = ["RedVC", "GreenVC", "BlueVC", "PinkVC"]
var whiteVC: WhiteController? //the one from the storyboard
var nav: UINavigationController? //this will represent the DetailNavigationController from Apple's MasterDetailApp
override func viewDidLoad() {
super.viewDidLoad()
splitViewController?.delegate = self
splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.allVisible
//1st instantiate the WhiteVC that was created in storyboard
self.whiteVC = storyboard?.instantiateViewController(withIdentifier: "WhiteController") as? WhiteController
//2nd add it to the programmatic navigationController as it's root
self.nav = UINavigationController(rootViewController: whiteVC!)
//3rd use the splitVC method to show the nav on the right side of scene
splitViewController?.showDetailViewController(self.nav!, sender: self
}
现在启动时,场景将如下所示:
现在回答如何在不包括 WhiteVC 的情况下推动任何颜色 vcs 的问题。您所要做的就是将任何颜色的 vc 作为根添加到作为类变量创建的编程导航中。在 tableView 里面didSelectRow
是你添加它并显示的地方
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.row{
case 0:
let redVC = storyboard?.instantiateViewController(withIdentifier: "RedController") as! RedController
self.nav = UINavigationController(rootViewController: redVC)
splitViewController?.showDetailViewController(self.nav! , sender: self)
break
case 1:
let greenVC = storyboard?.instantiateViewController(withIdentifier: "GreenController") as! GreenController
self.nav = UINavigationController(rootViewController: greenVC)
splitViewController?.showDetailViewController(self.nav! , sender: self)
break
case 2:
let blueVC = storyboard?.instantiateViewController(withIdentifier: "BlueController") as! BlueController
self.nav = UINavigationController(rootViewController: blueVC)
splitViewController?.showDetailViewController(self.nav! , sender: self)
break
case 3:
let pinkVC = storyboard?.instantiateViewController(withIdentifier: "PinkController") as! PinkController
self.nav = UINavigationController(rootViewController: PinkVC)
splitViewController?.showDetailViewController(self.nav! , sender: self)
break
}
现在,如果您选择了标记为 RedVC 的单元格,您会得到这个(RedVC 顶部应该有一个导航栏,但我忘了在 Photoshop 中添加它):
如果您查看 didSelectRow 内部,您将看到导航现在有一个新根,即 redVC(它最初在 viewDidLoad 中使用 WhiteVC)。由于您更改了根,WhiteVC 不再在层次结构中。对于任何其他颜色,同样的事情也会发生。如果你选择 PinkVC,你会得到(PinkVC 顶部应该有一个导航栏,但我忘了在 Photoshop 中添加它):
在任何情况下,您所要做的就是为导航设置一个新的根。如果您想添加将视图向外扩展的双展开箭头
您还可以将其添加到 didSelectRow
case 0:
let redVC = storyboard?.instantiateViewController(withIdentifier: "RedController") as! RedController
self.nav = UINavigationController(rootViewController: redVC)
//these 2 lines of code are what adds the double expand arrow
self.nav?.topViewController?.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
self.nav?.topViewController?.navigationItem.leftItemsSupplementBackButton = true
splitViewController?.showDetailViewController(self.nav! , sender: self)
break
//add the same exact 2 lines for every other case
最后一件事。这是我遇到的一个大问题,我相信其他人可能会遇到这个问题,因为这个 SplitVC 不是 root。假设在启动时的选项卡零上,您想显示另一个 vc(即 OrangeVC)而不是 SettingsVC。问题是设置是:
TabBarContoller > TabZeroSplitVC > TabZeroNavVC > SettingsVC
由于故事板将 SettingsVC 作为 TabZeroNavVC 的根目录,因此您必须在 appDelegate 的 didFinishLaunching(或您的登录屏幕等)中更改它。
使用它的代码是:
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//I subclassed the TabBarVC with the name TabBarController
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarVC: TabBarController = mainStoryboard.instantiateViewController(withIdentifier: "TabBarController") as! TabBarController
tabBarController.selectedIndex = 0
//first you have to get to the splitVC on the first tab
let tabZeroSplitVC = tabBarController.viewControllers![0] as! TabZeroSplitController
//second you have to get to the navVC that's connected to the splitVC
let tabZeroNavVC = tabZeroSplitVC.childViewControllers[0] as! TabZeroNavController
//third instantiate the vc that you want to appear upon launch
let orangeVC = mainStoryboard.instantiateViewController(withIdentifier: "OrangeController") as! OrangeController
//the navVC has a method to set a new array of vcs. Just add the orangeVC in here (make sure to put it in array brackets)
tabZeroNavVC.setViewControllers( [orangeVC], animated: true)
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
一旦你启动你的 OrangeVC 就会显示出来。由于 OrangeVC 不是 tableView,您可能希望显示全屏。请务必添加 UISplitViewControllerDelegate 并在 viewDidLoad 添加:
OrangeVC: UIViewController, UISplitViewControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
splitViewController?.delegate = self
//this will hide splitScreen and will only show fullScreen
splitViewController?.preferredDisplayMode = UISplitViewControllerDisplayMode.primaryHidden
}
启动时您将拥有一个橙色的全屏,而不是拆分屏幕。
尽管这些链接使用 SplitVC 作为 root,但这些是一些关于配置 SplitVC 的非常好的博客文章:
拆分VC-1
拆分VC-2
拆分VC-3
拆分VC-4
拆分VC-5
拆分VC-7