【问题标题】:UISplitViewController with nav stacks in both master and detail - how to remove a VC from one of the stacks?UISplitViewController 与主和详细导航堆栈 - 如何从堆栈之一中删除 VC?
【发布时间】:2017-11-28 01:11:58
【问题描述】:

我正在调试总是很有趣的遗留代码。旧代码试图模拟 splitView 委托方法,导致各种问题 - 主要是崩溃:在纵向的 Plus 设备上,旋转到横向导致崩溃 - 如果没有设置详细视图,旧代码试图创建一个在一个狡猾的黑客中,它只是没用......

我的应用是基于UISplitViewController 的,我在splitView 的主侧和细节侧都有一个导航堆栈。

通过阅读 SO 并使用 this example 并能够实现 UISplitViewController 委托方法,并且在旋转方面一切正常,并在适当时显示正确的主/详细视图。这是我的实现:(为代码墙sn-ps道歉)

- (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 委托方法 - 请参阅代码中的 cmets 了解我遇到的问题。

- (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 具有下一个/上一个按钮,用于选择 tableview 菜单类类 (AEContentMenuTableViewController) 的 tableview 中的下一行。我有一个委托函数,它可以告诉我当前 AECourseHTML... 正在使用来自 AEContentMenu...indexPath,当调用它时,它会选择菜单表视图行并实例化一个新的 AECourseHTML... 并推送它。

这就是我卡住的地方。在纵向中,按下一个/上一个很好,它会选择正确的行并按预期工作。但是一旦我旋转设备,主视图和详细视图都会显示详细视图。我可以在主视图上按“返回”,它会将我带到正确的 AEContentMenu... 类。如代码 sn-p cmets 中所述,我需要从主堆栈(实际上是第一个对象)中删除一个 ViewController,并且 AEContentMenu... 应该成为该堆栈的第一个对象 - 所以在旋转时,应该是主视图.

为这么长的帖子道歉,我已经为此烦恼了好几个星期,我想在这个问题中包含尽可能多的信息。提前致谢。

【问题讨论】:

    标签: ios objective-c uinavigationcontroller uisplitviewcontroller iphone-6-plus


    【解决方案1】:

    我找到了一个非常适合我的用例的解决方案。它可能不是最干净的代码,但我对我所拥有的感到满意。

    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;
    }
    

    【讨论】:

      【解决方案2】:

      你的顶级 if 语句应该返回 nil。由于您要返回嵌套导航控制器,因此您错过了弹出主导航顶部控制器的默认行为,这是必需的,因此可以将其放置在右侧。

      默认行为会找到嵌套的导航控制器并弹出它。但是,您仍然需要自己搜索它的原因是,如果它不存在,那么您需要像您所做的那样从情节提要中加载详细导航。

      【讨论】:

        猜你喜欢
        • 2020-12-07
        • 1970-01-01
        • 1970-01-01
        • 2019-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-09
        • 2018-06-09
        相关资源
        最近更新 更多