Swift 显示为popover的UIViewController是否可以是其自己的PopoOverPresentationController委托?

Swift 显示为popover的UIViewController是否可以是其自己的PopoOverPresentationController委托?,swift,uiviewcontroller,popover,uipresentationcontroller,Swift,Uiviewcontroller,Popover,Uipresentationcontroller,在下面显示的项目中,有一个InitialViewController,它有一个标记为“ShowPopover”的按钮。当点击该按钮时,应用程序应将第二个视图控制器(PopoverViewController)显示为popover。第二个视图控制器只有一个标签,上面写着“Popover!” 如果InitialViewController负责实例化PopoverViewController,检索popoverPresentationController,然后将popoverPresentation

在下面显示的项目中,有一个
InitialViewController
,它有一个标记为“ShowPopover”的按钮。当点击该按钮时,应用程序应将第二个视图控制器(
PopoverViewController
)显示为popover。第二个视图控制器只有一个标签,上面写着“Popover!”

如果
InitialViewController
负责实例化
PopoverViewController
,检索
popoverPresentationController
,然后将popoverPresentationController的
委托设置为自身(设置为
InitialViewController
),则此操作正常。您可以在下面看到结果:

但是,为了实现最大的可重用性,如果
InitialViewController
不需要知道演示控制器是如何委派的,那就太好了。我认为
PopoverViewController
应该可以将自己设置为popoverPresentationController的
委托。我已经在
viewDidLoad
pooverviewcontroller
viewwillbeen
功能中尝试过这一点。但是,在这两种情况下,
PopoverViewController
都以模式显示,如下所示:

import UIKit

// MARK: - UIViewController subclass

class InitialViewController: UIViewController {

    struct Lets {
        static let storyboardName = "Main"
        static let popoverStoryboardID = "Popover View Controller"
    }

    @IBAction func showPopoverButton(_ sender: UIButton) {

        // instantiate & present the popover view controller
        let storyboard = UIStoryboard(name: Lets.storyboardName,
                                      bundle: nil )
        let popoverViewController =
            storyboard.instantiateViewController(withIdentifier: Lets.popoverStoryboardID )
        popoverViewController.modalPresentationStyle = .popover
        guard let popoverPresenter = popoverViewController.popoverPresentationController
            else {
                fatalError( "could not retrieve a pointer to the 'popoverPresentationController' property of popoverViewController")
        }
        present(popoverViewController,
                animated: true,
                completion: nil )

        // Retrieve and configure UIPopoverPresentationController
        // after presentation (per
        // https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller)

        popoverPresenter.permittedArrowDirections = .any
        let button = sender
        popoverPresenter.sourceView = button
        popoverPresenter.sourceRect = button.bounds

    }
}
import UIKit


// MARK: - main UIViewController subclass

class PopoverViewController: UIViewController {

    // MARK: API
    var factorForMarginsAroundButton: CGFloat = 1.2

    // MARK: outlets and actions
    @IBOutlet weak var popoverLabel: UILabel!

    // MARK: lifecycle

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear( animated )

        // set the preferred size for popover presentations
        let labelSize =
            popoverLabel.systemLayoutSizeFitting( UILayoutFittingCompressedSize )
        let labelWithMargins =
            CGSize(width: labelSize.width * factorForMarginsAroundButton,
                   height: labelSize.height * factorForMarginsAroundButton )
        preferredContentSize = labelWithMargins

        // set the delegate for the popoverPresentationController to self
        popoverPresentationController?.delegate = self

    }
}
// MARK: - UIPopoverPresentationControllerDelegate
//       (inherits from protocol UIAdaptivePresentationControllerDelegate)

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

所有代码仅包含在
InitialViewController
PopoverViewController
中。
InitialViewController
故障版本中使用的代码如下所示:

import UIKit

// MARK: - UIViewController subclass

class InitialViewController: UIViewController {

    struct Lets {
        static let storyboardName = "Main"
        static let popoverStoryboardID = "Popover View Controller"
    }

    @IBAction func showPopoverButton(_ sender: UIButton) {

        // instantiate & present the popover view controller
        let storyboard = UIStoryboard(name: Lets.storyboardName,
                                      bundle: nil )
        let popoverViewController =
            storyboard.instantiateViewController(withIdentifier: Lets.popoverStoryboardID )
        popoverViewController.modalPresentationStyle = .popover
        guard let popoverPresenter = popoverViewController.popoverPresentationController
            else {
                fatalError( "could not retrieve a pointer to the 'popoverPresentationController' property of popoverViewController")
        }
        present(popoverViewController,
                animated: true,
                completion: nil )

        // Retrieve and configure UIPopoverPresentationController
        // after presentation (per
        // https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller)

        popoverPresenter.permittedArrowDirections = .any
        let button = sender
        popoverPresenter.sourceView = button
        popoverPresenter.sourceRect = button.bounds

    }
}
import UIKit


// MARK: - main UIViewController subclass

class PopoverViewController: UIViewController {

    // MARK: API
    var factorForMarginsAroundButton: CGFloat = 1.2

    // MARK: outlets and actions
    @IBOutlet weak var popoverLabel: UILabel!

    // MARK: lifecycle

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear( animated )

        // set the preferred size for popover presentations
        let labelSize =
            popoverLabel.systemLayoutSizeFitting( UILayoutFittingCompressedSize )
        let labelWithMargins =
            CGSize(width: labelSize.width * factorForMarginsAroundButton,
                   height: labelSize.height * factorForMarginsAroundButton )
        preferredContentSize = labelWithMargins

        // set the delegate for the popoverPresentationController to self
        popoverPresentationController?.delegate = self

    }
}
// MARK: - UIPopoverPresentationControllerDelegate
//       (inherits from protocol UIAdaptivePresentationControllerDelegate)

extension PopoverViewController: UIPopoverPresentationControllerDelegate
{
    func adaptivePresentationStyle(for controller: UIPresentationController,
                                   traitCollection: UITraitCollection)
        -> UIModalPresentationStyle{
            return .none
    }
}
失败
PopOverview控制器
中的代码如下所示:

import UIKit

// MARK: - UIViewController subclass

class InitialViewController: UIViewController {

    struct Lets {
        static let storyboardName = "Main"
        static let popoverStoryboardID = "Popover View Controller"
    }

    @IBAction func showPopoverButton(_ sender: UIButton) {

        // instantiate & present the popover view controller
        let storyboard = UIStoryboard(name: Lets.storyboardName,
                                      bundle: nil )
        let popoverViewController =
            storyboard.instantiateViewController(withIdentifier: Lets.popoverStoryboardID )
        popoverViewController.modalPresentationStyle = .popover
        guard let popoverPresenter = popoverViewController.popoverPresentationController
            else {
                fatalError( "could not retrieve a pointer to the 'popoverPresentationController' property of popoverViewController")
        }
        present(popoverViewController,
                animated: true,
                completion: nil )

        // Retrieve and configure UIPopoverPresentationController
        // after presentation (per
        // https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller)

        popoverPresenter.permittedArrowDirections = .any
        let button = sender
        popoverPresenter.sourceView = button
        popoverPresenter.sourceRect = button.bounds

    }
}
import UIKit


// MARK: - main UIViewController subclass

class PopoverViewController: UIViewController {

    // MARK: API
    var factorForMarginsAroundButton: CGFloat = 1.2

    // MARK: outlets and actions
    @IBOutlet weak var popoverLabel: UILabel!

    // MARK: lifecycle

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear( animated )

        // set the preferred size for popover presentations
        let labelSize =
            popoverLabel.systemLayoutSizeFitting( UILayoutFittingCompressedSize )
        let labelWithMargins =
            CGSize(width: labelSize.width * factorForMarginsAroundButton,
                   height: labelSize.height * factorForMarginsAroundButton )
        preferredContentSize = labelWithMargins

        // set the delegate for the popoverPresentationController to self
        popoverPresentationController?.delegate = self

    }
}
// MARK: - UIPopoverPresentationControllerDelegate
//       (inherits from protocol UIAdaptivePresentationControllerDelegate)

extension PopoverViewController: UIPopoverPresentationControllerDelegate
{
    func adaptivePresentationStyle(for controller: UIPresentationController,
                                   traitCollection: UITraitCollection)
        -> UIModalPresentationStyle{
            return .none
    }
}
显示为popover的视图控制器是否可以作为其自己的
PopoOverPresentationController
的代理


我使用的是Xcode 8.0、Swift 3.1,目标是iOS 10.0,这当然是可能的。你在处理一个时间问题。您需要在出现
视图之前设置代理。不幸的是,没有方便的视图生命周期函数来插入分配,所以我改为这样做

PopoverViewController
类中,在重写的getter中分配代理。如果你愿意,你可以把作业设为有条件的。这将创建一个永久关系,因此其他代码不会通过分配它来“覆盖”委托

override var popoverPresentationController: UIPopoverPresentationController? {
    get {
        let ppc = super.popoverPresentationController
        ppc?.delegate = self
        return ppc
    }
}

谢谢你,艾伦!我刚试过,效果很好。我同意这是一个时间问题,但我不知道覆盖属性会提供正确的时间。你能告诉我们你是怎么想出来的吗?老实说,一点尝试和错误。我发现初始化后popoverPresentationController还不存在,viewDidLoad已经很晚了。所以我在系统的任何部分中插入了我自己,使用popoverPresentationControllerHmm,我想我明白了。除非popoverPresentationController已经初始化并使用,否则ViewDidLoad不会发生,因此popoverPresentationController的获取必须在初始化之后、ViewDidLoad之前。再次感谢您的友好(非常迅速)回复。