下面是我的解决方案。它开始类似于 greenisus 的解决方案,通过挂钩UISplitViewController
的工具栏按钮事件处理程序。我在控制器中使用一个标志来跟踪弹出框是否打开。最后,为了处理用户打开弹出框,然后通过单击弹出框外部将其关闭的情况,我实现了UIPopoverControllerDelegate
协议。
一、控制器接口:
@interface LaunchScene : NSObject <UISplitViewControllerDelegate, UIPopoverControllerDelegate>
{
UISplitViewController* _splitViewController; //Shows list UITableView on the left, and details on the right
UIToolbar* _toolbar; //Toolbar for the button that will show the popover, when in portrait orientation
SEL _svcAction; //The action from the toolbar
id _svcTarget; //The target object from the toolbar
UIPopoverController* _popover; //The popover that might need to be dismissed
BOOL _popoverShowing; //Whether the popover is currently showing or not
}
-(void) svcToolbarClicked: (id)sender;
我使用 _svcAction 和 _svcTarget 来解决 greenisus 的担忧,即他可能没有调用正确的函数。
下面是我的实现。为简洁起见,我省略了实例化 UISplitViewController 和子视图的代码。 显示所有显示/隐藏相关代码。
//the master view controller will be hidden so hook the popover
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc
{
_popoverShowing = FALSE;
if(_toolbar == nil)
{
//set title of master button
barButtonItem.title = @"Title goes here";
//Impose my selector in between the SVController, and the SVController's default implementation
_svcTarget = barButtonItem.target;
_svcAction = barButtonItem.action;
barButtonItem.target = self;
barButtonItem.action = @selector(svcToolbarClicked:);
//create a toolbar
_toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 1024, 44)];
[_toolbar setItems:[NSArray arrayWithObject:barButtonItem] animated:YES];
}
//add the toolbar to the details view (the second controller in the splitViewControllers array)
UIViewController* temp = [_splitViewController.viewControllers objectAtIndex:1];
[temp.view addSubview:_toolbar];
}
这是我的函数,它响应工具栏的点击。这可以处理用户点击并重新点击工具栏按钮的情况。
-(void) svcToolbarClicked: (id)sender
{
if(_popoverShowing)
{
[_popover dismissPopoverAnimated:TRUE];
}
else
{
//Perform the default SVController implementation
[_svcTarget performSelector:_svcAction];
}
//Toggle the flag
_popoverShowing = !_popoverShowing;
}
UISplitViewControllerDelegate 中的一些函数
//the master view (non-popover) will be shown again (meaning it is going to landscape orientation)
- (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)button
{
//remove the toolbar
[_toolbar removeFromSuperview];
}
// the master view controller will be displayed in a popover (i.e. the button has been pressed, and the popover is about to be displayed.
//Unfortunately triggers when the popover is ALREADY displayed.
- (void)splitViewController:(UISplitViewController*)svc popoverController:(UIPopoverController*)pc willPresentViewController:(UIViewController *)aViewController
{
_popover = pc; //Grab the popover object
_popover.delegate = self;
}
上面的代码对于大多数情况来说已经足够了。但是,如果用户打开弹出框,然后通过单击屏幕上的其他位置将其关闭,则_popoverShowing
布尔值将包含不正确的值,这将迫使用户点击工具栏按钮两次以重新打开弹出框。要解决此问题,请实现该UIPopoverControllerDelegate
方法,如下面的代码片段。
//UIPopoverControllerDelegate method
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
_popoverShowing = FALSE;
_popover = nil;
}
这让我花了很长时间才弄清楚,深入研究文档和(我认为)StackOverflow 上的大多数 UISplitViewController 问题。我希望有人觉得它有用。如果是这样,我觊觎声望点。;-)