【问题标题】:How to present popover properly in iOS 8如何在 iOS 8 中正确显示弹出框
【发布时间】:2014-08-29 10:05:02
【问题描述】:

我正在尝试将 UIPopoverView 添加到我的 Swift iOS 8 应用程序中,但我无法访问 PopoverContentSize 属性,因为弹出框没有以正确的形状显示。我的代码:

var popover: UIPopoverController? = nil 

    func addCategory() {

    var newCategory = storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: newCategory)
    popover = UIPopoverController(contentViewController: nav)
    popover!.setPopoverContentSize(CGSizeMake(550, 600), animated: true)
    popover!.delegate = self
    popover!.presentPopoverFromBarButtonItem(self.navigationItem.rightBarButtonItem, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}

输出:

当我通过 UIPopoverPresentationController 做同样的事情时,我仍然没有完成它。这是我的代码:

func addCategory() {

    var popoverContent = self.storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
    var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.Popover
    var popover = nav.popoverPresentationController as UIPopoverPresentationController
    popover.delegate = self
    popover.popoverContentSize = CGSizeMake(1000, 300)
    popover.sourceView = self.view
    popover.sourceRect = CGRectMake(100,100,0,0)

    self.presentViewController(nav, animated: true, completion: nil)

}

我得到完全相同的输出。

如何自定义弹出框的大小?任何帮助将不胜感激!

【问题讨论】:

  • 开发者网站上有一个名为“A Look Inside Presentation Controllers”的 WWDC 视频,它解释了如何使用 UIPopoverPresentationController
  • 我已经根据关于 UIpopoverpresentationctontroller 的苹果视频编辑了我的问题,但没有任何改变!你有什么我应该改变的吗?感谢您的意见!

标签: ios swift uipopovercontroller ios8 uipopover


【解决方案1】:
 var popoverContent = (self.storyboard?.instantiateViewController(withIdentifier: "WhatsNewViewController"))! as UIViewController
        var nav = UINavigationController(rootViewController: popoverContent)
    nav.modalPresentationStyle = UIModalPresentationStyle.popover
        var popover = nav.popoverPresentationController
        popoverContent.preferredContentSize = CGSize(width: 500, height: 100)
        popover?.delegate = self
        popover?.sourceView = self.view
        popover?.sourceRect = CGRectMake(100,100,0,0)

    self.present(nav, animated: true, completion: nil)

【讨论】:

  • 在最新的 Xcode 中我们可以这样写
【解决方案2】:

对于那些想学习的人!

我为那些想要学习和使用 Popover 视图的人创建了一个开源项目。您可以在此处找到该项目。 https://github.com/tryWabbit/KTListPopup

【讨论】:

    【解决方案3】:

    以下是关于如何配置和呈现弹出框的非常全面的指南。 https://www.appcoda.com/presentation-controllers-tutorial/

    总之,一个可行的实现(对 Swift 4.2 的原始文章语法进行了一些更新),然后从其他地方调用,如下所示:

    func showPopover(ofViewController popoverViewController: UIViewController, originView: UIView) {
        popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
        if let popoverController = popoverViewController.popoverPresentationController {
            popoverController.delegate = self
            popoverController.sourceView = originView
            popoverController.sourceRect = originView.bounds
            popoverController.permittedArrowDirections = UIPopoverArrowDirection.any
        }
        self.present(popoverViewController, animated: true)
    }
    

    @mmc 的回答中已经涵盖了很多内容,但这篇文章有助于解释一些使用的代码元素,并展示了如何扩展它。

    它还提供了许多关于使用委托来处理 iPhone 与 iPad 的演示样式的额外细节,并允许在全屏显示时取消弹出框。再次为 Swift 4.2 更新:

    func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle {
        //return UIModalPresentationStyle.fullScreen
        return UIModalPresentationStyle.none
    }
    
    func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        if traitCollection.horizontalSizeClass == .compact {
            return UIModalPresentationStyle.none
            //return UIModalPresentationStyle.fullScreen
        }
        //return UIModalPresentationStyle.fullScreen
        return UIModalPresentationStyle.none
    }
    
    func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        switch style {
        case .fullScreen:
            let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
            let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(doneWithPopover))
            navigationController.topViewController?.navigationItem.rightBarButtonItem = doneButton
            return navigationController
        default:
            return controller.presentedViewController
        }
    }
    
    // As of Swift 4, functions used in selectors must be declared as @objc
    @objc private func doneWithPopover() {
        self.dismiss(animated: true, completion: nil)
    }
    

    希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      xcode 9.1 / swift 4 我的两分钱。

      class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
      
          override func viewDidLoad(){
              super.viewDidLoad()
      
              let when = DispatchTime.now() + 0.5
      
              DispatchQueue.main.asyncAfter(deadline: when, execute: { () -> Void in
                  // to test after 05.secs... :)
                  self.showPopover(base: self.view)
      
              })
      
      }
      
      
      func showPopover(base: UIView) {
          if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "popover") as? PopOverViewController {
      
              let navController = UINavigationController(rootViewController: viewController)
              navController.modalPresentationStyle = .popover
      
              if let pctrl = navController.popoverPresentationController {
                  pctrl.delegate = self
      
                  pctrl.sourceView = base
                  pctrl.sourceRect = base.bounds
      
                  self.present(navController, animated: true, completion: nil)
              }
          }
      }
      
      
      @IBAction func onShow(sender: UIButton){
          self.showPopover(base: sender)
      }
      
      func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle{
          return .none
      }
      

      并在以下方面进行实验:

      func 自适应PresentationStyle...

          return .popover
      

      或: 返回 .pageSheet.... 等等..

      【讨论】:

        【解决方案5】:

        其实比这简单得多。在情节提要中,您应该制作要用作弹出框的视图控制器,并像往常一样为其创建一个视图控制器类。从要打开弹出框的对象中进行如下所示的转场,在本例中为名为“Config”的UIBarButton

        在“mother viewcontroller”中实现UIPopoverPresentationControllerDelegate和委托方法:

        func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
            //do som stuff from the popover
        }
        

        像这样覆盖prepareForSeque 方法:

        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
             //segue for the popover configuration window
            if segue.identifier == "yourSegueIdentifierForPopOver" {
                if let controller = segue.destinationViewController as? UIViewController {
                    controller.popoverPresentationController!.delegate = self
                    controller.preferredContentSize = CGSize(width: 320, height: 186)
                }
            }
        }
        

        你就完成了。您现在可以将弹出视图视为任何其他视图,即。添加字段,什么不!并且您可以通过使用UIPopoverPresentationController 中的popoverPresentationController.presentedViewController 方法来获取内容控制器。

        在 iPhone 上你也必须覆盖

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

        【讨论】:

          【解决方案6】:

          在您的视图控制器中实现 UIAdaptivePresentationControllerDelegate。 然后添加:

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

          【讨论】:

            【解决方案7】:

            在 iOS9 UIPopoverController 已被贬值。所以iOS9.x以上的Objective-C版本可以使用下面的代码,

            - (IBAction)onclickPopover:(id)sender {
            UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
            UIViewController *viewController = [sb instantiateViewControllerWithIdentifier:@"popover"];
            
            viewController.modalPresentationStyle = UIModalPresentationPopover;
            viewController.popoverPresentationController.sourceView = self.popOverBtn;
            viewController.popoverPresentationController.sourceRect = self.popOverBtn.bounds;
            viewController.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
            [self presentViewController:viewController animated:YES completion:nil]; }
            

            【讨论】:

            • 这个问题专门针对 Swift,而不是针对 Objective-C。
            【解决方案8】:

            Swift 2.0

            好吧,我解决了。看一看。在 StoryBoard 中制作了一个 ViewController。与 PopOverViewController 类相关联。

            import UIKit
            
            class PopOverViewController: UIViewController {
                override func viewDidLoad() {
                    super.viewDidLoad()    
                    self.preferredContentSize = CGSizeMake(200, 200)    
                    self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss:")    
                }    
                func dismiss(sender: AnyObject) {
                    self.dismissViewControllerAnimated(true, completion: nil)
                }
            }      
            

            查看视图控制器:

            //  ViewController.swift
            
            import UIKit
            
            class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
            {
                func showPopover(base: UIView)
                {
                    if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("popover") as? PopOverViewController {    
            
                        let navController = UINavigationController(rootViewController: viewController)
                        navController.modalPresentationStyle = .Popover
            
                        if let pctrl = navController.popoverPresentationController {
                            pctrl.delegate = self
            
                            pctrl.sourceView = base
                            pctrl.sourceRect = base.bounds
            
                            self.presentViewController(navController, animated: true, completion: nil)
                        }
                    }
                }    
                override func viewDidLoad(){
                    super.viewDidLoad()
                }    
                @IBAction func onShow(sender: UIButton)
                {
                    self.showPopover(sender)
                }    
                func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
                    return .None
                }
            }  
            

            注意:func showPopover(base: UIView) 方法应该放在 ViewDidLoad 之前。希望对您有所帮助!

            【讨论】:

            • 嗨@Alvin,我将从地图注释中弹出一个视图。所以我做了和你一样的事。不同之处在于我将填充 tableviewcontroller 而不是视图。现在问题不在于委托方法。“popoverPresentationControllerDidDismissPopover”。当我解雇控制器时。你能帮我吗 ? (问题与帖子无关)
            • 为什么showPopover(base: UIView)方法应该放在viewDidLoad()之前?
            【解决方案9】:

            在这里,我将“Joris416”Swift 代码转换为 Objective-c,

            -(void) popoverstart
            {
                ViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"PopoverView"];
                UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:controller];
                nav.modalPresentationStyle = UIModalPresentationPopover;
                UIPopoverPresentationController *popover = nav.popoverPresentationController;
                controller.preferredContentSize = CGSizeMake(300, 200);
                popover.delegate = self;
                popover.sourceView = self.view;
                popover.sourceRect = CGRectMake(100, 100, 0, 0);
                popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
                [self presentViewController:nav animated:YES completion:nil];
            }
            
            -(UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller
            {
                return UIModalPresentationNone;
            }
            

            记得添加
            UIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate

            【讨论】:

            • 这个问题专门针对 Swift,而不是针对 Objective-C。
            【解决方案10】:

            我在上面制作了一个 Objective-C 版本的 Imagine Digitals 快速答案。我不认为我错过了什么,因为它似乎在初步测试中工作,如果你发现了什么,请告诉我,我会更新它

            -(void) presentPopover
            {
                YourViewController* popoverContent = [[YourViewController alloc] init]; //this will be a subclass of UIViewController
                UINavigationController* nav =  [[UINavigationController alloc] initWithRootViewController:popoverContent];
                nav.modalPresentationStyle = UIModalPresentationPopover;
                UIPopoverPresentationController* popover = nav.popoverPresentationController;
                popoverContent.preferredContentSize = CGSizeMake(500,600);
                popover.delegate = self;
                popover.sourceRect = CGRectMake(100,100,0,0); //I actually used popover.barButtonItem = self.myBarButton;
            
                [self presentViewController:nav animated:YES completion:nil];
            }
            

            【讨论】:

            • 我想你漏掉了popover.sourceView = self.view;
            • 这个问题专门针对 Swift,而不是针对 Objective-C。
            • 我意识到这一点,但是即使您正在搜索objective-C,谷歌也会将您带到这里。我就是这样来到这里的。
            【解决方案11】:

            好的,一个室友看了看,想通了:

             func addCategory() {
            
                var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
                var nav = UINavigationController(rootViewController: popoverContent)
                nav.modalPresentationStyle = UIModalPresentationStyle.Popover
                var popover = nav.popoverPresentationController
                popoverContent.preferredContentSize = CGSizeMake(500,600)
                popover.delegate = self
                popover.sourceView = self.view
                popover.sourceRect = CGRectMake(100,100,0,0)
            
                self.presentViewController(nav, animated: true, completion: nil)
            
            }
            

            就是这样。

            您不再与弹出框本身对话,而是通过调用属性preferredContentSize 与其中的视图控制器对话以设置内容大小

            【讨论】:

            • 可能是显而易见的,但这不仅仅是与 swift 相关的。我还必须在我的 obj-c 应用程序中执行此操作 :)
            • 对代码的另一个注释 - 您可以使用“let”而不是“var”。 Apple 建议您在不需要重新分配值的情况下使用它。
            • 这是 iPhone GM 中的错误。如果您尝试在模拟器处于纵向时进行演示,则它始终是全屏的。如果你旋转到横向,它就会变成一个弹出框。如果您再次旋转回纵向,它将保持弹出窗口。
            • 解决方案是在调用 presentViewController 之前设置弹出框。这与 Apple 的示例完全相反,他们明确告诉您在调用 presentViewController 之后设置弹出框。
            • @PsychoDad 你能提供你提到的这个解决方案的链接吗?我仍然停留在“当模拟器处于纵向时,它总是全屏”。谢谢
            【解决方案12】:

            这在iOS8 Day-by-Day blog上得到了最好的解释

            简而言之,一旦您将 UIViewController 的 modalPresentationStyle 设置为 .Popover,您就可以通过控制器的 popoverPresentationController 属性获取 UIPopoverPresentationClass(一个新的 iOS8 类)。

            【讨论】:

              【解决方案13】:

              我找到了一个完整示例,说明如何让这一切正常工作,以便您可以始终显示弹出框,无论设备/方向如何https://github.com/frogcjn/AdaptivePopover_iOS8_Swift

              关键是实现UIAdaptivePresentationControllerDelegate

              func adaptivePresentationStyleForPresentationController(PC: UIPresentationController!) -> UIModalPresentationStyle {
                  // This *forces* a popover to be displayed on the iPhone
                  return .None
              }
              

              然后扩展上面的例子(来自 Imagine Digital):

              nav.popoverPresentationController!.delegate = implOfUIAPCDelegate
              

              【讨论】:

              • 我使用 UIPopoverPresentationControllerDelegate
              • 正确,UIPopoverPresentationControllerDelegate 扩展了 UIAdaptivePresentationControllerDelegate。因此,根据定义,两者都包含方法“adaptivePresentationStyleForPresentationController”。我提供了基本接口,因为苹果的 API 文档中记录了该方法。
              • 请注意,这是未记录的行为。文档说这个委托方法必须返回“UIModalPresentationFullScreenUIModalPresentationOverFullScreen”。此外,“如果您不实现此方法或返回除UIModalPresentationFullScreenUIModalPresentationOverFullScreen 之外的任何样式,则演示控制器会将演示样式调整为UIModalPresentationFullScreen 样式。”
              • 当前文档建议从 iOS 8.3 开始您应该使用 -adaptivePresentationStyleForPresentationController:traitCollection: 并且返回的样式必须是“UIModalPresentationFullScreen、UIModalPresentationOverFullScreen、UIModalPresentationFormSheet 或 UIModalPresentationNone。”
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-01-12
              • 1970-01-01
              • 2014-08-18
              • 1970-01-01
              相关资源
              最近更新 更多