【问题标题】:How do I hook into the action method for an iPad popover toolbar button?如何挂钩 iPad 弹出工具栏按钮的操作方法?
【发布时间】:2010-04-06 21:21:46
【问题描述】:

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

我试图弄清楚如果用户在显示弹出框时点击工具栏按钮,如何使弹出框消失。如果您点击弹出框外的任何位置,您可以在不选择项目的情况下使弹出框消失,但如果用户再次点击该按钮,我也想让它消失。

我遇到的问题是:似乎没有一种明显、简单的方法可以连接到工具栏按钮的操作中。我可以知道,使用调试器,在按钮上调用的操作是 showMasterInPopover。我承认,我不熟悉以编程方式使用选择器。

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

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

谢谢!

【问题讨论】:

    标签: ipad uipopovercontroller popover uisplitview


    【解决方案1】:

    所以事实证明,您可以通过如下实现 SplitViewController willPresentViewController 方法来使单击 barButtonItem 时弹出框消失:

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

          以下是我的解决方案。它开始类似于 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 方法,如下面的 sn-p。

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

          这让我花了很长时间才弄清楚,深入研究了 StackOverflow 上的文档和(我认为)大多数 UISplitViewController 问题。我希望有人觉得它有用。如果是这样,我觊觎声望点。 ;-)

          【讨论】:

          • 哇,谢谢!我一定会试试这个,让你知道它是否有效:-)
          【解决方案5】:

          也许你们都把事情复杂化了,或者我读到的东西与你们想要做的完全不同……但也许,这就是你们所有人都想弄清楚的:

          -(void)togglePopOverController {
          
          if ([popOverController isPopoverVisible]) {
          
          [popOverController dismissPopoverAnimated:YES];
          
          } else {
          
          [popOverController presentPopoverFromBarButtonItem:bbiOpenPopOver permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
          
          }
          
          }
          

          【讨论】:

          • 嗯,棘手的部分是弄清楚在哪里挂钩到 splitViewController 委托方法。请参阅下面的解决方案。
          【解决方案6】:

          伊丽莎白写道:

          如果您点击弹出框外的任何位置,您可以在不选择项目的情况下使弹出框消失,但如果用户再次点击该按钮,我也想让它消失。

          首先,我要说的是,我要说的任何内容都不是针对个人的——我不是这个意思。这一切都来自多年设计编程界面和研究 Apple 人机界面指南(以及拥有一位不断尝试教我正确做事方式的图形设计师)。这是一种相反的观点,而不是咆哮。

          您的建议对我来说是 UI 方面的问题,并且会在 Apple 审核应用程序时引起麻烦。您永远不应该让已知 UI 对象执行它无法正常执行的功能(例如:按钮 从不 显示 然后 释放视图/对象/window. 切换执行此操作)。

          例如,导航栏上的放大镜表示搜索(Apple 定义)。他们过去和将来都会继续拒绝使用它来缩放界面的应用程序。例如:Apple Rejects ConvertBotThe Odyssey: Trail of Tears(搜索页面)。拒绝中的语言总是相同的(粗体标出他们会引用的内容):

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

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

          只是我的 $.02

          【讨论】:

          • 这种行为非常标准,我在很多应用程序上都看到过(以及 Apple 的 Web 应用程序文档看起来像一个弹出框 - 它也这样做)。
          • @Jann 查看 iBooks 或 Instapaper。我同意伊丽莎白和马可的观点:twitter.com/marcoarment/status/11767179703
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-16
          相关资源
          最近更新 更多