iOS UISplitViewController在竖屏模式下推出新视图控制器后,弹出控制器按钮消失了。

7
在我的UISplitViewController应用程序中,我有以下内容:
  • RootViewController - 左侧窗格中的视图控制器。
  • DetailViewController - 右侧窗格中的视图控制器。
当在RootViewController中的一项(位于UITableView中)被点击时,将设置新的视图控制器,如下所示:

[detailViewController setViewControllers:[NSArray arrayWithObjects:newViewController, nil] animated:animated];

//detailPane是我的DetailViewController

所有功能在横屏模式下都运作良好。然而,在纵向模式下,我无法使UISplitViewController按我想要的方式工作,也就是说,当我在纵向模式下启动和使用应用程序时,RootViewController的弹出按钮在我的DetailViewController中没有适当地显示。
当我在纵向模式下启动应用程序时,弹出按钮会适当地显示。但是,当我在弹出窗口中点击一个项目并设置了一个新的视图控制器后,按钮消失了。我必须将设备旋转到横向模式,然后再次旋转到纵向模式才能使按钮再次出现。
我在我的应用程序AppDelegate中设置了UISplitViewController的代理,如下所示:

self.splitViewController.delegate = self.detailViewController

以下是我的UISplitViewControllerDelegate实现:
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem  forPopoverController: (UIPopoverController*)pc {
    NSLog(@"Will hide view controller");
    barButtonItem.title = @"Menu";
    [self.navigationItem setLeftBarButtonItem:barButtonItem];
    self.popoverController = pc;
}

- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {
    NSLog(@"Will show view controller")
    NSMutableArray *items = [self.navigationItem.leftBarButtonItems mutableCopy];
    [items removeAllObjects];
    [self.navigationItem setLeftBarButtonItems:items animated:YES];
    [items release];
    self.popoverController = nil;   
}

任何提示或帮助都将不胜感激。 谢谢。

你解决了吗?我也遇到同样的问题。 - Joris Weimar
4个回答

4

我设计了一种新解决方案。

子类化 UINavigationController 并实现 UISplitViewControllerDelegate。将此类的一个实例设置为 splitViewController 的右侧 ViewController。每当您想从 master 更改详细视图控制器时,就可以使用此方法。

NewDetailViewController *newDetailVC = ....// Obtain the new detail VC

newDetailVC.navigationItem.leftBarButtonItem = [[[[self.splitViewController.viewControllers objectAtIndex:1]topViewController]navigationItem ]leftBarButtonItem];  //With this you tet a pointer to the button from the first detail VC but from the new detail VC

[[self.navigationController.splitViewController.viewControllers objectAtIndex:1]setViewControllers:[NSArray arrayWithObject:newDetailVC]];  //Now you set the new detail VC as the only VC in the array of VCs of the subclassed navigation controller which is the right VC of the split view Controller

这对我很有用,我可以避免定义一个完整的协议并将主控设置为代理,这是一个很大的折衷。希望能帮到你。

好的解决方案,但是在我尝试使用它旋转后会崩溃。 - amcc
你是通过编程、IB还是使用Storyboard设置子类导航控制器的? - Cato

3
如果您仍需要它:

http://developer.apple.com/library/ios/#samplecode/MultipleDetailViews/Introduction/Intro.html

我曾经遇到和你类似的问题,我做了以下修改来解决它:

我让主视图控制器(在我的情况下是UITableViewController)成为UISplitViewController的代理。在UISplitViewController的两个代理方法中(也就是在你的主视图控制器实现中),你需要将弹出视图控制器和工具栏按钮保存在你的类中。现在,如果你想要改变详情视图控制器,你可以这样做:

self.viewControllers = [NSArray arrayWithObjects:[self.viewControllers objectAtIndex:0], newDetailsViewController, nil];

UIViewController <SubstitutableDetailViewController>*vc = (UIViewController <SubstitutableDetailViewController>*)newDetailsViewController;

[vc invalidateRootPopoverButtonItem:_tableViewController.rootPopoverButtonItem];
[_createReportViewController showRootPopoverButtonItem:_tableViewController.rootPopoverButtonItem];

我们所拥有的地方

@protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
@end

您需要为每个detailsViewController实现的代理。您可以像这样实现:
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
    self.navigationItem.leftBarButtonItem = barButtonItem;
}

- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
    self.navigationItem.leftBarButtonItem = nil;
}

如果这对您有帮助,请告诉我。


2

我喜欢Nekto的解决方案,但它忽略了一个关键问题。

不清楚action:选择器会导致UISplitViewController在弹出窗口中显示MasterViewController。当我通过调试器检查BarButtonItem最终弄清楚时,我才意识到为什么这么难以弄清楚:这个action:选择器在苹果的iOS SDK中没有任何文档记录。糟糕。

尝试一下:

UIBarButtonItem *showListView = [[UIBarButtonItem alloc] initWithTitle:@"List" style:UIBarButtonItemStyleBordered target:[self splitViewController] action:@selector(toggleMasterVisible:)];
[[detailViewController navigationItem] setLeftBarButtonItem:showListView];        

你可能希望用条件语句来检查窗口是否处于竖屏模式,例如if ([self interfaceOrientation] == UIInterfaceOrientationPortrait)


你好,Andrew。我一直在使用你的“toggleMasterVisible:”解决方案,一切都很正常。但是当我将Xcode更新到5版本后,它显示“未声明选择器”...那么现在我该如何强制主按钮出现呢? - Japa

0

当您设置放置在导航堆栈上的新视图控制器时,可能会重置所有导航按钮。更改导航堆栈后,您可以手动添加适当的按钮。

例如,您可以从- (void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)pc中选择代码,其中创建默认弹出窗控制器按钮:

UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"Menu" style:UIBarButtonItemStyleBordered target:self action:@selector(appropriateSelector)];
[self.navigationItem setLeftBarButtonItem:barButtonItem];
self.popoverController = pc;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接