【问题标题】:UIPopoverPresentationController on iOS 8 iPhoneiOS 8 iPhone 上的 UIPopoverPresentationController
【发布时间】:2014-10-08 18:17:01
【问题描述】:

有人知道UIPopoverPresentationController 是否可用于在 iPhone 上显示弹出框吗?想知道 Apple 是否在 iOS 8 上添加了此功能,以尝试为 iPad 和 iPhone 创建更统一的演示控制器。

不确定是否可以通过 Beta 提问/回答问题。在这种情况下我会删除它。

【问题讨论】:

    标签: objective-c iphone uipopovercontroller ios8 uipopover


    【解决方案1】:

    您可以使用 adaptivePresentationStyleForPresentationController: 方法可通过UIPopoverPresentationController.delegate 获得。

    UIPresentationController 使用此方法询问要使用的新演示样式,在您的情况下,只需返回 UIModalPresentationNone 将导致 UIPopoverPresentationController 呈现为弹出窗口而不是全屏。

    这是一个使用故事板中的 segue 设置的弹出框示例,从 UIBarButtonItem 到“present modallyUIViewController

    class SomeViewController: UIViewController, UIPopoverPresentationControllerDelegate {
    
        // override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { // swift < 3.0
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "PopoverSegue" {
                if let controller = segue.destinationViewController as? UIViewController {
                    controller.popoverPresentationController.delegate = self
                    controller.preferredContentSize = CGSize(width: 320, height: 186)                
                }
            }
        }
    
        // MARK: UIPopoverPresentationControllerDelegate
    
        //func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle { // swift < 3.0
        func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
            // Return no adaptive presentation style, use default presentation behaviour
            return .None
        }
    }
    

    WWDC 2014 session 214 "View Controller Advancement in iOS8" (36:30) 中提到了这个技巧

    【讨论】:

    • 这是 iPhone GM 中的错误。如果您尝试在模拟器处于纵向时进行演示,则它始终是全屏的。如果你旋转到横向,它就会变成一个弹出框。如果您再次旋转回纵向,它将保持弹出窗口。
    • 解决方案是在调用 presentViewController 之前设置弹出框。这与 Apple 的示例完全相反,他们明确告诉您在调用 presentViewController 之后设置弹出框。
    • obj-c 中的同一段代码,供不懂 Swift 的人使用:stackoverflow.com/a/28143620/1228075
    • @PsychoDad 是对的。我的逻辑感和信任感都崩溃了。不相信任何人,甚至不相信 WWDC 视频和 Apple 课程参考。
    • @Daniel 确实。无论如何,在演示之前设置它会更有意义,Apple 可能会在发布之前更改它。
    【解决方案2】:

    如果有人只想显示带有代码的弹出框,您可以使用以下方法。

    目标 - C

    声明UIPopoverPresentationController的属性:

    @property(nonatomic,retain)UIPopoverPresentationController *dateTimePopover8;
    

    使用以下方法从 UIButton 呈现弹出框:

    - (IBAction)btnSelectDatePressed:(id)sender
    {
        UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
        dateVC.preferredContentSize = CGSizeMake(280,200);
        destNav.modalPresentationStyle = UIModalPresentationPopover;
        _dateTimePopover8 = destNav.popoverPresentationController;
        _dateTimePopover8.delegate = self;
        _dateTimePopover8.sourceView = self.view;
        _dateTimePopover8.sourceRect = sender.frame;
        destNav.navigationBarHidden = YES;
        [self presentViewController:destNav animated:YES completion:nil];
    }
    

    使用以下方法从 UIBarButtonItem 呈现弹出框:

    - (IBAction)btnSelectDatePressed:(id)sender
    {
        UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
        dateVC.preferredContentSize = CGSizeMake(280,200);
        destNav.modalPresentationStyle = UIModalPresentationPopover;
        _dateTimePopover8 = destNav.popoverPresentationController;
        _dateTimePopover8.delegate = self;
        _dateTimePopover8.sourceView = self.view;
         CGRect frame = [[sender valueForKey:@"view"] frame];
        frame.origin.y = frame.origin.y+20;
        _dateTimePopover8.sourceRect = frame;
        destNav.navigationBarHidden = YES;
        [self presentViewController:destNav animated:YES completion:nil];
    }
    

    在你的视图控制器中也实现这个委托方法:

    - (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
        return UIModalPresentationNone;
    }
    

    要关闭此弹出框,只需关闭视图控制器即可。下面是关闭视图控制器的代码:

    -(void)hideIOS8PopOver
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    

    SWIFT

    使用以下方法从 UIButton 呈现弹出框:

    func filterBooks(sender: UIButon)
        {
            let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
            var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
            filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
            let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
            popoverPresentationViewController?.permittedArrowDirections = .Any
            popoverPresentationViewController?.delegate = self
            popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
            popoverPresentationViewController!.sourceView = self.view;
            popoverPresentationViewController!.sourceRect = sender.frame
    
            filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
            filterDistanceViewController.navigationBarHidden = true
            self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
        }
    

    使用以下方法从 UIBarButtonItem 呈现弹出框:

    func filterBooks(sender: UIBarButtonItem)
        {
            let filterVC =  FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
            var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
            filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
            let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
            popoverPresentationViewController?.permittedArrowDirections = .Any
            popoverPresentationViewController?.delegate = self
            popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
            popoverPresentationViewController!.sourceView = self.view;
            var frame:CGRect = sender.valueForKey("view")!.frame
            frame.origin.y = frame.origin.y+20
            popoverPresentationViewController!.sourceRect = frame
    
            filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
            filterDistanceViewController.navigationBarHidden = true
            self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
        }
    

    在你的视图控制器中也实现这个委托方法:

    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle{
            return .None
        }
    

    请务必在 .h/.m/.swift 文件中添加委托 UIPopoverPresentationControllerDelegate

    【讨论】:

    • 这在 iOS8/Swift 横屏模式下的 iPhone 上效果很好
    • 我认为不需要声明 UIPopoverPresentationController。当我简单地访问它并通过目标视图控制器设置它的属性时,它对我有用。我正在使用 Swift 和 Xcode 6.2。
    • destNav.popoverPresentationController 为零。
    • 如果您遇到此问题,请转至 documentation where Apple incorrectly describes how to configure the popover 帮助其他人,然后单击反馈按钮并建议他们更正代码列表。
    • 不适用于我的情况:dateVC 在没有情节提要的情况下初始化
    【解决方案3】:

    问题: iPhone 弹出框显示全屏并且不尊重preferredContentSize 值。

    解决方案:与 Apple 在 UIPopoverPresentationController 类参考中的建议相反,在获得对弹出框呈现控制器的引用并配置它之后呈现视图控制器。

    // Get the popover presentation controller and configure it.
    //...
    
    // Present the view controller using the popover style.
    [self presentViewController:myPopoverViewController animated: YES completion: nil]; 
    

    【讨论】:

    • 同样的事情,实现委托并不够,配置后呈现在 iPhone 6S iOS 10.1 上完成了技巧
    • 只需要在presentViewController之前设置delegate,
    【解决方案4】:

    确保实现UIAdaptivePresentationControllerDelegate

    像这样:

    - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
        return UIModalPresentationNone;
    }
    

    如果您不想要全屏弹出框

    【讨论】:

      【解决方案5】:

      我找到了一些解决方法。

      在 Xcode6.1 上,使用 presentationController.delegate 而不是 popoverPresentationController.delegate

      - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
      {
          if ([segue.identifier compare:@"showPopOver"] == NSOrderedSame) {
              UINavigationController * nvc = segue.destinationViewController;
              UIPresentationController * pc = nvc.presentationController;
              pc.delegate = self;
          }
      }
      
      #pragma mark == UIPopoverPresentationControllerDelegate ==
      - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
      {
          return UIModalPresentationNone;
      }
      

      在 WWDC 2014 “View Controller Advancements in iOS8”中,以下代码可以在 iPhone 上显示弹出框。

      - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
      {
      
          UINavigationController * nvc = segue.destinationViewController;
          UIPopoverPresentationController * pvc = nvc.popoverPresentationController;
          pvc.delegate = self;
      }
      
      #pragma mark == UIPopoverPresentationControllerDelegate ==
      - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
      {
          return UIModalPresentationNone;
      }
      

      但在 Xcode 6.1 上,这些代码显示全屏演示... (nvc.popoverPresentationController 为零)

      我怀疑这可能是 Apple 的错误。

      【讨论】:

        【解决方案6】:

        在 iOS 8.3 及更高版本中,在UIPopoverPresentationControllerDelegate 协议中使用以下语法来覆盖弹出窗口的UIModalPresentationStyle

        func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
            return .none
        }
        

        【讨论】:

          【解决方案7】:

          在您的 WEBVIEW 类中添加这两个方法。并添加

          -(void) prepareForSegue: (UIStoryboardSegue * ) segue sender: (id) sender {
              // Assuming you've hooked this all up in a Storyboard with a popover presentation style
              if ([segue.identifier isEqualToString: @"showPopover"]) {
                  UINavigationController * destNav = segue.destinationViewController;
                  pop = destNav.viewControllers.firstObject;
                  // This is the important part
                  UIPopoverPresentationController * popPC = destNav.popoverPresentationController;
                  popPC.delegate = self;
              }
          }
          
          - (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
              return UIModalPresentationNone;
          }
          

          【讨论】:

            【解决方案8】:

            您可以像这样扩展 UIPopoverPresentationControllerDelegate:

            protocol PopoverPresentationSourceView {}
            extension UIBarButtonItem : PopoverPresentationSourceView {}
            extension UIView : PopoverPresentationSourceView {}
            
            extension UIPopoverPresentationControllerDelegate where Self : UIViewController {
               func present(popover: UIViewController, 
                    from sourceView: PopoverPresentationSourceView, 
                    size: CGSize, arrowDirection: UIPopoverArrowDirection) {
            
                  popover.modalPresentationStyle = .popover
                  popover.preferredContentSize = size
                  let popoverController = popover.popoverPresentationController
                  popoverController?.delegate = self
                  if let aView = sourceView as? UIView {
                      popoverController?.sourceView = aView
                      popoverController?.sourceRect = CGRect(x: aView.bounds.midX, y: aView.bounds.midY, width: 0, height: 0)
                  } else if let barButtonItem = sourceView as? UIBarButtonItem {
                      popoverController?.barButtonItem = barButtonItem
                  }
                  popoverController?.permittedArrowDirections = arrowDirection
                  present(popover, animated: true, completion: nil)
               }
            }
            

            您现在可以从任何实现UIPopoverPresentationControllerDelegate 的视图控制器调用present(popover: from: size: arrowDirection: ),例如。

            class YourViewController : UIViewController {
                @IBAction func someButtonPressed(_ sender: UIButton) {
                    let popover = SomeViewController()
                    present(popover: popover, from: sender, size: CGSize(width: 280, height: 400), arrowDirection: .right)
                }
            }
            
            extension YourViewController : UIPopoverPresentationControllerDelegate {
                func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
                    return .none
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-08-18
              • 1970-01-01
              • 2017-05-13
              • 1970-01-01
              • 2015-02-11
              • 1970-01-01
              • 2014-12-11
              • 2014-11-24
              相关资源
              最近更新 更多