如何连接 iPad 弹出工具栏按钮的操作方法?

发布于 2024-08-27 17:54:27 字数 575 浏览 8 评论 0原文

我正在使用分割视图模板创建一个简单的分割视图,当然,它在纵向模式下有一个弹出窗口。我正在使用模板生成的默认代码,该代码添加/删除工具栏项目并设置弹出窗口控制器并将其删除。这两个方法是 splitViewController:willShowViewController:... 和 splitViewController:willHideViewController:...

我试图弄清楚如果用户在显示弹出窗口时点击工具栏按钮,如何使弹出窗口消失。如果您点击弹出窗口之外的任何位置,您可以使弹出窗口消失而无需选择项目,但我也希望在用户再次点击按钮时使其消失。

我陷入困境的是:似乎没有一种明显、简单的方法来挂钩工具栏按钮的操作。我可以使用调试器得知在按钮上调用的操作是 showMasterInPopover。我承认,我对以编程方式使用选择器还很陌生。

我可以以某种方式编写一个操作并将其设置在工具栏项上,而不覆盖已经存在的操作吗?例如添加一个调用现在存在的操作?或者我是否必须自己编写一个显示/隐藏弹出窗口的操作(现在大概由分割视图控制器在幕后完成的行为???)。

或者我是否缺少一种简单的方法来将此行为添加到此按钮而不更改为我设置的现有行为?

谢谢你!

I am using the split view template to create a simple split view that has, of course, a popover in Portrait mode. I'm using the default code generated by template that adds/removes the toolbar item and sets the popover controller and removes it. These two methods are splitViewController:willShowViewController:... and splitViewController:willHideViewController:...

I'm trying to figure out how to make the popover disappear if the user taps on the toolbar button while the popover is displayed. You can make the popover disappear without selecting an item if you tap anywhere outside the popover, but I would also like to make it disappear if the user taps the button again.

Where I'm stuck is this: there doesn't seem to be an obvious, easy way to hook into the action for the toolbar button. I can tell, using the debugger, that the action that's being called on the button is showMasterInPopover. And I am new to working with selectors programmatically, I admit.

Can I somehow write an action and set it on the toolbar item without overriding the action that's already there? e.g. add an action that calls the one that's there now? Or would I have to write an action that shows/hides the popover myself (behavior that's being done behind the scenes presumably by the split view controller now???).

Or am I missing an easy way to add this behavior to this button without changing the existing behavior that's being set up for me?

Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦醒时光 2024-09-03 17:54:28

没有代表做出真正的评论。 :-(

@Jann - 我很确定 Elizabeth 想要做的事情是非常标准的。例如,当您按下左上角的工具栏按钮时,iPad 上预装的 Notes 应用程序会关闭并打开弹出窗口。

Don't have the rep to make a real comment. :-(

@Jann - I'm pretty sure what Elizabeth wants to do is pretty standard. For example, the Notes application that ships pre-loaded on the iPad closes and opens the popover when you press the toolbar button in the top left corner.

攒眉千度 2024-09-03 17:54:28

以下是我的解决方案。它的开始类似于 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 问题。我希望有人觉得它有用。如果是这样,我就垂涎声望点了。 ;-)

Below is my solution. It starts out similar to greenisus' solution, by hooking the UISplitViewController's toolbar button event handler. I use a flag in my controller to track whether the popover is open or not. Finally, to handle the case where the user opens the popover, then closes it by clicking outside the popover, I implement the UIPopoverControllerDelegate protocol.

First, the controller interface:

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

I use _svcAction and _svcTarget to addess greenisus' worries that he might not be calling the right function.

Below is my implementation. For brevity, I have omitted the code that instantiates the UISplitViewController and the subviews. All the show/hide related code is shown.

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

Here is my function, that responds to the toolbar click. This handles the case where the user taps and re-taps the toolbar button.

-(void) svcToolbarClicked: (id)sender
{
    if(_popoverShowing)
    {
        [_popover dismissPopoverAnimated:TRUE];
    }
    else 
    {
        //Perform the default SVController implementation
        [_svcTarget performSelector:_svcAction];
    }
    //Toggle the flag
    _popoverShowing = !_popoverShowing;
}

Some functions from 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;
}

The above code is sufficient for most cases. However, if the user opens the popover, then dismisses by clicking elsewhere on the screen, the _popoverShowing boolean will contain an incorrect value, which will force the user to tap the toolbar button twice to re-open the popover. To fix this, implement the UIPopoverControllerDelegate method, like the snippet below.

//UIPopoverControllerDelegate method
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
    _popoverShowing = FALSE;
    _popover = nil;
}

This took me forever to figure out, digging through the docs and (I think) most of the UISplitViewController questions on StackOverflow. I hope somebody finds it useful. If so, I covet reputation points. ;-)

不甘平庸 2024-09-03 17:54:28

也许你们把事情搞得太复杂了,或者我读到了一些与你们想做的完全不同的东西……但也许,这就是你们都想弄清楚的如此艰难:

-(void)togglePopOverController {

if ([popOverController isPopoverVisible]) {

[popOverController dismissPopoverAnimated:YES];

} else {

[popOverController presentPopoverFromBarButtonItem:bbiOpenPopOver permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

}

}

Maybe you all just complicate it too much or I have read something very different than you guys wanted to do... but perhaps, this is what you were all trying to figure out so hardish:

-(void)togglePopOverController {

if ([popOverController isPopoverVisible]) {

[popOverController dismissPopoverAnimated:YES];

} else {

[popOverController presentPopoverFromBarButtonItem:bbiOpenPopOver permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

}

}
情仇皆在手 2024-09-03 17:54:28

伊丽莎白写道:

如果您点击弹出窗口之外的任何位置,您可以使弹出窗口消失而无需选择任何项目,但我也希望在用户再次点击该按钮时使其消失。

首先,我要声明的是,我接下来所说的一切都不是针对个人的——事实并非如此。这一切都源于多年的编程界面设计和苹果人机界面指南的研究(以及一位不断尝试教我做事的正确方法的平面设计师)。它的意思是反对观点,而不是咆哮。

你所建议的对我来说是一个 UI 方面的问题,并且当苹果审查该应用程序时,这将是一个导致麻烦的问题。您永远不应该让已知的 UI 对象执行它无法正常执行的功能(例如:按钮从不显示然后释放视图/对象/窗口执行此操作)。

例如,导航栏上的放大镜意味着搜索(由 Apple 定义)。他们过去并且将来会继续拒绝使用此功能来缩放界面的应用程序。例如: Apple 拒绝 ConvertBotThe Odyssey: Trail of Tears(搜索页面)。拒绝中的语言始终相同(粗体标记他们将引用的内容供您使用):

“...以非标准方式使用标准 iPhone/iPod 屏幕图像,可能会导致用户混淆。更改标准 iPhone 图形、操作和图像的行为,或模拟这些图形、操作或图像的失败均违反了 iPhone 开发者计划协议,该协议要求应用程序遵守人机界面指南.”

另外,如果您真的想要此功能,请问问自己:“为什么?”。如果是因为你自己喜欢,那我真的会跳过它。大多数用户会对这种行为感到困惑,并且实际上不会使用它,因为他们不知道这是一个可以使用的选项。苹果在过去 3 年里一直在培训 iPhoneOS 用户如何使用他们的操作系统和界面元素。作为程序员或设计师,您最不想做的就是花时间尝试培训用户如何使用您的应用程序。他们通常会从设备中删除您的应用,然后转移到另一个类似的应用,而不是强迫自己学习的做事方式。

只是我的 $.02

Elisabeth writes:

You can make the popover disappear without selecting an item if you tap anywhere outside the popover, but I would also like to make it disappear if the user taps the button again.

First of all, let me say that none of what I am about to say is to be taken personally -- it is not meant that way. It all comes from years of designing programming interfaces and studying the Apple Human Interface Guidelines (as well as having a Graphic Designer who is contstantly trying to teach me the right way to do things). It is meant as an opposing viewpoint and not as a rant.

What you are suggesting is a problem UI-wise for me, and will be an issue that causes trouble when Apple reviews the app. You are never supposed to have a known-UI-object perform a function that it does not perform normally (For instance: a button never shows and then releases a view/object/window. Toggles do this).

For instance, a magnifying glass on the navbar means Search (as defined by Apple). They have in the past, and will continue in the future to, refuse apps that use this for zooming the interface. For example: Apple Rejects ConvertBot or The Odyssey: Trail of Tears (search the page for it). The language in the rejection is always the same (bold marking what they would cite for your usage):

“… uses standard iPhone/iPod screen images in a non-standard way, potentially resulting in user confusion. Changing the behavior of standard iPhone graphics, actions, and images, or simulating failures of those graphics, actions, or images is a violation of the iPhone Developer Program agreement which requires applications to abide by the Human Interface Guidelines.”

Also, if you really want this feature, ask yourself: "Why?". If it is because you, yourself, like it, then I would really skip it. Most users would be confused by this behavior and would not actually use it because they would not know it was an option to use. Apple spent the last 3 years training iPhoneOS users how to use their OS and interface elements. The last thing you, as a programmer or designer, want to do is spend time trying to train a user on how to use your app. They will generally remove your app from their device and move to another similar app instead of forcing themselves to learn your way of doing things.

Just my $.02

绻影浮沉 2024-09-03 17:54:27

因此,事实证明,您可以通过实现 SplitViewController willPresentViewController 方法,在单击 barButtonItem 时使弹出窗口关闭,如下所示:

- (void) splitViewController:(UISplitViewController *)svc 
           popoverController: (UIPopoverController *)pc
   willPresentViewController: (UIViewController *)aViewController
{
    if (pc != nil) {
        [pc dismissPopoverAnimated:YES];
    }
}

So it turns out that you can make the popover dismiss when clicking on the barButtonItem by implementing the SplitViewController willPresentViewController method as follows:

- (void) splitViewController:(UISplitViewController *)svc 
           popoverController: (UIPopoverController *)pc
   willPresentViewController: (UIViewController *)aViewController
{
    if (pc != nil) {
        [pc dismissPopoverAnimated:YES];
    }
}
吲‖鸣 2024-09-03 17:54:27

因此,barButtonItem 将以 UISplitViewController 作为目标,以 showMasterInPopover: 作为操作。我在文档中找不到它,所以我有点担心调用它是不行的,但我通过将目标更改为 self (视图控制器)并将操作更改为自定义方法来使其工作,例如这:

- (void)showMasterInPopover:(id)sender {
    // ...insert custom stuff here...
    [splitViewController showMasterInPopover:sender];
}

So, the barButtonItem will have the UISplitViewController as the target and showMasterInPopover: as the action. I can't find it in the documentation, so I'm a bit worried it's not okay to call it, but I got it to work by changing the target to self (the view controller) and the action to a custom method, like this:

- (void)showMasterInPopover:(id)sender {
    // ...insert custom stuff here...
    [splitViewController showMasterInPopover:sender];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文