UISplitViewController 在主要和详细信息中都带有导航堆栈 - 如何从其中一个堆栈中删除 VC?
UISplitViewController with nav stacks in both master and detail - how to remove a VC from one of the stacks?
我正在调试遗留代码,这总是很有趣。旧代码试图模拟 splitView
委托方法,导致各种问题 - 主要是崩溃:在纵向的 Plus 设备上,旋转到横向导致崩溃 - 如果没有详细视图集,旧代码试图在一个狡猾的黑客中创建一个,它只是没用......
我的应用程序是基于 UISplitViewController
的,我在 splitView 的主侧和详细侧都有一个导航堆栈。
通过阅读 SO 并使用 this example 并能够实现 UISplitViewController
委托方法,并且在旋转方面一切正常,并在适当的时候显示正确的 master/detail 视图.这是我的实现:(为代码片段墙道歉)
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
if ([secondaryViewController isKindOfClass:[UINavigationController class]]
&& [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[AECourseHTMLTableViewController class]]
&& ([(AECourseHTMLTableViewController *)[(UINavigationController *)secondaryViewController topViewController] htmlContentEntry] == nil)) {
// If the detail controller doesn't have an item, display the primary view controller instead
return YES;
}
return NO;
}
还有另一个 splitView 委托方法 - 请参阅代码中的注释以了解我遇到的问题。
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController {
// If detail view already exists
if ([primaryViewController isKindOfClass:[UINavigationController class]]) {
for (UIViewController *controller in [(UINavigationController *)primaryViewController viewControllers]) {
if ([controller isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)controller visibleViewController] isKindOfClass:[AECourseHTMLTableViewController class]]) {
return controller;
}
}
}
// Create detail view
UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:@"CourseHTMLNav"];
if ([navController.viewControllers.firstObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
AECourseHTMLTableViewController *courseViewController = navController.viewControllers.firstObject;
[self configureViewController:courseViewController entry:self.contentSection.sections[0] indexPath:courseViewController.currentIndexPath];
}
// Enable back button
UIViewController *controller = [navController visibleViewController];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
if (!self.splitViewController.isCollapsed) {
UINavigationController *navController = self.splitViewController.viewControllers.firstObject;
AEContentMenuTableViewController *contentMenuVC = navController.viewControllers.firstObject; // This controller needs to be master in Landscape
NSMutableArray<UIViewController *> *controllers = [navController.viewControllers mutableCopy]; // Contains 3 controllers, first needs removed
NSMutableArray *toDelete = [NSMutableArray new];
for (UIViewController *viewController in controllers)
if ([viewController isKindOfClass:[contentMenuVC class]] || [viewController isKindOfClass:[AECourseHTMLTableViewController class]]) {
[toDelete addObject:viewController]; // Remove first VC, so master should become AEContentMenuVC?
break;
}
// Remove the object
[controllers removeObjectsInArray:toDelete];
// Set viewControllers
navController.viewControllers = controllers;
}
return navController;
}
AECourseHTMLTableViewController
有 next/prev 个按钮 select tableview 菜单的 tableview 中的下一行 class class (AEContentMenuTableViewController
) .我有一个委托函数可以告诉我当前 indexPath
其中 AECourseHTML...
从 AEContentMenu...
使用,并且在调用它时,它 select 是菜单表视图行并实例化一个新的 AECourseHTML...
并推送它。
这就是我卡住的地方。在纵向中,按 next/prev 没问题,它 select 是正确的行并且按预期工作。但是一旦我旋转设备,主视图和详细视图都会显示详细视图。我可以在主视图上按 "Back",它会将我带到正确的 AEContentMenu...
class。如代码片段注释中所述,我需要从主堆栈(实际上是第一个对象)中删除一个 ViewController,并且 AEContentMenu...
应该成为该堆栈的第一个对象 - 所以在旋转时,应该成为主视图。
很抱歉这么长时间post,我已经为此苦思了好几个星期了,我想在这个问题中包含尽可能多的信息。提前致谢。
我找到了适合我的用例的解决方案。它可能不是最干净的代码,但我对我得到的代码很满意。
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
保持不变。我已经用解决方案更新了我的 splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
委托方法。欢迎任何反馈。
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController {
// If detail view already exists
if ([primaryViewController isKindOfClass:[UINavigationController class]]) {
for (UIViewController *controller in [(UINavigationController *)primaryViewController viewControllers]) {
if ([controller isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)controller visibleViewController] isKindOfClass:[AECourseHTMLTableViewController class]]) {
return controller;
}
}
}
// Return CourseVC
UINavigationController *navController = splitViewController.viewControllers.firstObject;
UIViewController *viewController;
for (viewController in navController.viewControllers) {
if ([navController.viewControllers.lastObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
return viewController;
} else {
// Create detail view
UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:@"CourseHTMLNav"];
if ([navController.viewControllers.firstObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
// Enable back button
UIViewController *controller = [navController visibleViewController];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
AECourseHTMLTableViewController *courseViewController = navController.viewControllers.firstObject;
// If next/prev has been tapped, configure current ContentHTML
if (self.currentContentHTML) {
[self configureViewController:courseViewController entry:self.currentContentHTML indexPath:courseViewController.currentIndexPath];
} else {
// Create new ContentHTML from first row of AEContentMenuVC
[self configureViewController:courseViewController entry:self.contentSection.sections[0] indexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
}
return navController;
}
}
}
return navController;
}
你最上面的 if 语句应该 return nil。由于您 return 使用嵌套导航控制器,因此您错过了弹出主导航顶部控制器的默认行为,这是必需的,因此可以将其放置在右侧。
默认行为会找到嵌套的导航控制器并将其弹出。然而,您仍然需要自己搜索它的原因是,如果它不存在,那么您需要像您所做的那样从情节提要中加载详细导航。
我正在调试遗留代码,这总是很有趣。旧代码试图模拟 splitView
委托方法,导致各种问题 - 主要是崩溃:在纵向的 Plus 设备上,旋转到横向导致崩溃 - 如果没有详细视图集,旧代码试图在一个狡猾的黑客中创建一个,它只是没用......
我的应用程序是基于 UISplitViewController
的,我在 splitView 的主侧和详细侧都有一个导航堆栈。
通过阅读 SO 并使用 this example 并能够实现 UISplitViewController
委托方法,并且在旋转方面一切正常,并在适当的时候显示正确的 master/detail 视图.这是我的实现:(为代码片段墙道歉)
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
if ([secondaryViewController isKindOfClass:[UINavigationController class]]
&& [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[AECourseHTMLTableViewController class]]
&& ([(AECourseHTMLTableViewController *)[(UINavigationController *)secondaryViewController topViewController] htmlContentEntry] == nil)) {
// If the detail controller doesn't have an item, display the primary view controller instead
return YES;
}
return NO;
}
还有另一个 splitView 委托方法 - 请参阅代码中的注释以了解我遇到的问题。
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController {
// If detail view already exists
if ([primaryViewController isKindOfClass:[UINavigationController class]]) {
for (UIViewController *controller in [(UINavigationController *)primaryViewController viewControllers]) {
if ([controller isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)controller visibleViewController] isKindOfClass:[AECourseHTMLTableViewController class]]) {
return controller;
}
}
}
// Create detail view
UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:@"CourseHTMLNav"];
if ([navController.viewControllers.firstObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
AECourseHTMLTableViewController *courseViewController = navController.viewControllers.firstObject;
[self configureViewController:courseViewController entry:self.contentSection.sections[0] indexPath:courseViewController.currentIndexPath];
}
// Enable back button
UIViewController *controller = [navController visibleViewController];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
if (!self.splitViewController.isCollapsed) {
UINavigationController *navController = self.splitViewController.viewControllers.firstObject;
AEContentMenuTableViewController *contentMenuVC = navController.viewControllers.firstObject; // This controller needs to be master in Landscape
NSMutableArray<UIViewController *> *controllers = [navController.viewControllers mutableCopy]; // Contains 3 controllers, first needs removed
NSMutableArray *toDelete = [NSMutableArray new];
for (UIViewController *viewController in controllers)
if ([viewController isKindOfClass:[contentMenuVC class]] || [viewController isKindOfClass:[AECourseHTMLTableViewController class]]) {
[toDelete addObject:viewController]; // Remove first VC, so master should become AEContentMenuVC?
break;
}
// Remove the object
[controllers removeObjectsInArray:toDelete];
// Set viewControllers
navController.viewControllers = controllers;
}
return navController;
}
AECourseHTMLTableViewController
有 next/prev 个按钮 select tableview 菜单的 tableview 中的下一行 class class (AEContentMenuTableViewController
) .我有一个委托函数可以告诉我当前 indexPath
其中 AECourseHTML...
从 AEContentMenu...
使用,并且在调用它时,它 select 是菜单表视图行并实例化一个新的 AECourseHTML...
并推送它。
这就是我卡住的地方。在纵向中,按 next/prev 没问题,它 select 是正确的行并且按预期工作。但是一旦我旋转设备,主视图和详细视图都会显示详细视图。我可以在主视图上按 "Back",它会将我带到正确的 AEContentMenu...
class。如代码片段注释中所述,我需要从主堆栈(实际上是第一个对象)中删除一个 ViewController,并且 AEContentMenu...
应该成为该堆栈的第一个对象 - 所以在旋转时,应该成为主视图。
很抱歉这么长时间post,我已经为此苦思了好几个星期了,我想在这个问题中包含尽可能多的信息。提前致谢。
我找到了适合我的用例的解决方案。它可能不是最干净的代码,但我对我得到的代码很满意。
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
保持不变。我已经用解决方案更新了我的 splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
委托方法。欢迎任何反馈。
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController {
// If detail view already exists
if ([primaryViewController isKindOfClass:[UINavigationController class]]) {
for (UIViewController *controller in [(UINavigationController *)primaryViewController viewControllers]) {
if ([controller isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)controller visibleViewController] isKindOfClass:[AECourseHTMLTableViewController class]]) {
return controller;
}
}
}
// Return CourseVC
UINavigationController *navController = splitViewController.viewControllers.firstObject;
UIViewController *viewController;
for (viewController in navController.viewControllers) {
if ([navController.viewControllers.lastObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
return viewController;
} else {
// Create detail view
UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:@"CourseHTMLNav"];
if ([navController.viewControllers.firstObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
// Enable back button
UIViewController *controller = [navController visibleViewController];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
AECourseHTMLTableViewController *courseViewController = navController.viewControllers.firstObject;
// If next/prev has been tapped, configure current ContentHTML
if (self.currentContentHTML) {
[self configureViewController:courseViewController entry:self.currentContentHTML indexPath:courseViewController.currentIndexPath];
} else {
// Create new ContentHTML from first row of AEContentMenuVC
[self configureViewController:courseViewController entry:self.contentSection.sections[0] indexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
}
return navController;
}
}
}
return navController;
}
你最上面的 if 语句应该 return nil。由于您 return 使用嵌套导航控制器,因此您错过了弹出主导航顶部控制器的默认行为,这是必需的,因此可以将其放置在右侧。
默认行为会找到嵌套的导航控制器并将其弹出。然而,您仍然需要自己搜索它的原因是,如果它不存在,那么您需要像您所做的那样从情节提要中加载详细导航。