iOS UISplitViewController 的 Popover 控制器按钮在以纵向模式推送新视图控制器后消失
Posted
技术标签:
【中文标题】iOS UISplitViewController 的 Popover 控制器按钮在以纵向模式推送新视图控制器后消失【英文标题】:iOS UISplitViewController's Popover controller button disappear after pushing new view controller in portrait mode 【发布时间】:2011-10-25 06:50:48 【问题描述】:在我的 UISplitViewController 应用程序中,我有
RootViewController - 左窗格中的视图控制器。 DetailViewController - 右侧窗格中的视图控制器。当 RootViewController 中的一项(在 UITableView 中)被点击时,新的视图控制器将被设置如下所示:
[detailViewController setViewControllers:[NSArray arrayWithObjects:newViewController, nil] animated:animated];
//detailPane is my DetailViewController
在横向模式下一切都很好。但是,我无法让 UISplitViewController 在纵向模式下按我想要的方式工作,也就是说,当我在纵向模式下启动和使用应用程序时,RootViewController 的弹出按钮不会正确显示在我的 DetailViewController 中。
当我以纵向模式启动应用程序时,弹出按钮会适当显示。但是在点击弹出窗口中的一项并且在 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;
非常感谢任何提示或帮助。 谢谢。
【问题讨论】:
你解决了吗?我有同样的问题。 【参考方案1】:刚刚想出了一个新的解决方案。
子类UINavigationController
并实现UISplitViewControllerDelegate
。将这个类的一个实例设置为 splitViewController 的右 ViewController。每次您想从主控更改详细视图控制器时
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
这对我有用,我可以避免定义一个空洞协议并将主人设置为代表,这是一个很大的权衡。希望对您有所帮助。
【讨论】:
很好的解决方案,但是在使用它后尝试旋转时它崩溃了 您是在编程方式、IB 还是使用 Storyboard 中设置子类导航控制器?【参考方案2】:如果你还需要它:
http://developer.apple.com/library/ios/#samplecode/MultipleDetailViews/Introduction/Intro.html
我对我的来源做了什么(我和你有类似的设置)来修复它:
我有主视图控制器(在我的例子中是 UITableViewController)是 UISplitViewController 的代表。在 UISplitViewControllers 的两个委托方法中(因此这将在您的主视图控制器实现中),您将在您的类中保存 popupviewcontroller 和 barbuttonitem。现在,如果你改变你的细节视图控制器,你可以这样做:
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
每个 detailsViewControllers 都应该遵守的委托。你可以这样实现:
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
self.navigationItem.leftBarButtonItem = barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
self.navigationItem.leftBarButtonItem = nil;
如果这对您有帮助,请告诉我。
【讨论】:
【参考方案3】:我喜欢 Nekto 的解决方案,但它漏掉了一个关键问题。
不清楚action:
选择器会导致 UISplitViewController 在弹出窗口中显示 MasterViewController。当我最终弄清楚这一点时,通过检查调试器中的BarButtonItem
,我意识到为什么要弄清楚这一点如此棘手:action:
选择器在 Apple 的 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 时,它说“未声明的选择器”......所以我怎么能强制主按钮现在出现?【参考方案4】:当您在navigation stack
上设置新的视图控制器时,可能所有导航按钮都会被重置。您可以在更改navigation stack
后手动添加相应的按钮。
例如,您可以从创建默认弹出控制器按钮的- (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;
【讨论】:
以上是关于iOS UISplitViewController 的 Popover 控制器按钮在以纵向模式推送新视图控制器后消失的主要内容,如果未能解决你的问题,请参考以下文章
iOS (iPad) 在 UISplitViewController 中拖放
UISplitViewController 内的 iOS 13 UITabBarController 未正确折叠
嵌入 UISplitViewController 时,UINavigationBar 中缺少 iOS11 UISearchBar
转换为使用 iOS 8 Popover Segues 时 UISplitViewController 崩溃