UISplitViewController - 带有 UINavigationController 的多个细节视图

Posted

技术标签:

【中文标题】UISplitViewController - 带有 UINavigationController 的多个细节视图【英文标题】:UISplitViewController - multiple detail views with UINavigationController 【发布时间】:2012-02-14 13:20:25 【问题描述】:

我正在将 iPhone 应用程序转换为通用应用程序,并且将嵌套表转换为 UISplitViewController 排列几乎是直截了当的,但在 iPad 上运行时还有一个问题让我头疼。

为了通用应用兼容性,“主”视图包含一个 UINavigationController,用于在一系列 TableView 中导航,每个 TableView 都显示一个菜单。这很好用。

最终,用户到达详细视图中显示的内容。每个详细视图“链”都包含在 UINavigationController 中,因为某些视图可以向下钻取以显示地图等。其想法是弹出按钮将位于详细视图的根级别。请务必注意,每次选择该行时都会从头开始创建详细视图。

我研究了 Apple 的 Multiple Detail View Sample Code ,因此将主视图用作 UISplitViewController 委托,它提供隐藏/显示弹出框选择器,然后将调用传递给选择的替代细节视图。

在横向模式下工作时,我可以在主视图中选择不同的行,并且详细视图可以很好地切换 - 一切都很好。太棒了。

在纵向模式下,事情并不那么好......当旋转到纵向时,弹出按钮在当前选定的详细视图中正确显示,但在选择一行时消失(即它以某种方式未正确添加到新选择的视图的导航栏)。

我已经添加了诊断代码,看起来正在进行正确的调用(带有正确的指针)以在新选择的详细视图上显示弹出按钮。此外,我可以旋转到横向并再次返回,然后会出现弹出按钮,因此我对弹出 UIBarButtonItem 正确连接到新的细节 NavBar 感到相当满意。

由于在选择行之前不会创建详细视图,我想知道这是否是 UINavigationBar 在调用 showRootPopoverButtonItem 时未实例化的情况(基于 Apple 的示例代码)。这一理论得到了以下事实的支持:如果我旋转到横向并再次返回(如上所述)并选择相同的视图,则会出现弹出按钮。

我还在 Apple 的示例代码中看到了这条评论,在 didSelectRowAtIndexPath 中,在切换详细视图之前,请注意使用了“after”这个词...

// Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created).

所以,我尝试在 viewWillAppear 中再次调用 showRootPopoverButton 方法(此时 UINavigationBar 应该存在),但这也不会导致弹出按钮出现。

对于如何在纵向模式下从主视图中选择新行时如何让弹出按钮立即出现的任何想法和建议,我将不胜感激。谢谢。

感谢您阅读本文,相关代码如下。

从主视图,这里是 UISplitViewControllerDelegate 选择器,

- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc


    // Keep references to the popover controller and the popover button, and tell the detail view controller to show the button.
    barButtonItem.title = @"Root View Controller";
    self.popoverController = pc;
    self.rootPopoverButtonItem = barButtonItem;
    //UIViewController <SubstitutableDetailViewController> *detailViewController = [self.splitViewController.viewControllers objectAtIndex:1];

    // ^ Apple's example, commented out, my equivalent code to obtain
    // active detail navigation controller below,

    UINavigationController *detailNavController = [self.splitViewController.viewControllers objectAtIndex:1];
    UIViewController *detailViewController = detailNavController.visibleViewController;

    [detailViewController showRootPopoverButtonItem:rootPopoverButtonItem];



- (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem

     // Nil out references to the popover controller and the popover button, and tell the detail view controller to hide the button.
     UINavigationController *detailNavController = [self.splitViewController.viewControllers objectAtIndex:1];
     UIViewController *detailViewController = detailNavController.visibleViewController;
     [detailViewController invalidateRootPopoverButtonItem:rootPopoverButtonItem];
     self.popoverController = nil;
     self.rootPopoverButtonItem = nil;

而且,与 Apple 的示例非常相似,这是在主表中选择一行时发生的情况,

if (rootPopoverButtonItem != nil)

    NSLog (@"show popover button");
    [newDetailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];

从细节来看,

- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem

    NSLog (@"detailViewController (view: %p, button: %p, nav: %p): showRootPopoverButton", self, barButtonItem, self.navigationItem);

    barButtonItem.title = self.navigationItem.title;

    [self.navigationItem setLeftBarButtonItem:barButtonItem animated:NO];

    popoverButton = barButtonItem;



- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
    
    NSLog (@"detailViewController (%p): invalidateRootPopoverButton", self);

    // Called when the view is shown again in the split view, invalidating the button and popover controller.
    [self.navigationItem setLeftBarButtonItem:nil animated:NO];

    popoverButton = nil;

【问题讨论】:

【参考方案1】:

我认为有两件事可能是这里的问题。您应该包括其余的代码。特别是当用户在 master 中执行操作时更改详细视图控制器的部分。

    如果你刚刚实例化了detailNavControllervisibleViewController 可能为零。即使您将其设置为根,也没有“可见”视图控制器,因为它实际上还没有显示。您可能想尝试使用topViewController

    我不确定您是否在每次用户在主文件中选择某些内容时创建一个新的detailNavController,但如果是,您需要再次将rootPopoverButtonItem 传递给detailViewController,因为- (void)splitViewController: willHideViewController: withBarButtonItem: forPopoverController: 只会在方向改变时自动调用。

【讨论】:

谢谢!您回答的第 1 部分使我走上了正确的道路。我花了太长时间才弄清楚这一点,感谢您的帮助。 谢谢!我为解决这个问题所做的是将对 rootPopoverButtonItem 的引用存储在我的单例类中——似乎运行良好。

以上是关于UISplitViewController - 带有 UINavigationController 的多个细节视图的主要内容,如果未能解决你的问题,请参考以下文章

UISplitViewController - 并排或纵向叠加

在 UIViewControllers 和 UISplitViewController 之间导航 [关闭]

将 UIToolBar 放在 UISplitViewController 上方?

UISplitViewController + UISearchController 显示搜索细节

iPad 上的 UITraitCollection 和 UISplitViewController

UISplitViewController 没有正确显示