swift 以弹出窗口形式显示的UIViewController是否可以是其自己的popoverPresentationController委托?

nbysray5  于 2022-10-31  发布在  Swift
关注(0)|答案(2)|浏览(239)

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

如果InitialViewController负责示例化PopoverViewController,检索popoverPresentationController,然后将popoverPresentationController的delegate设置为自身(InitialViewController),则此操作可以正常工作。

然而,为了最大限度地提高可重用性,如果InitialViewController不需要知道表示控制器是如何被委托的,那就太好了。我认为PopoverViewController应该可以将自己设置为popoverPresentationController的delegate。我已经在viewDidLoadPopoverViewControllerviewWillAppear函数中尝试过这种方法。然而,PopoverViewController在两种情况下都是模态表示的,如下所示:

所有代码仅包含在InitialViewControllerPopoverViewController中。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

    }
}

失败PopoverViewController中的代码如下所示:

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
    }
}

作为弹出窗口显示的视图控制器是否可以作为其自己的popoverPresentationController的委托?
我使用Xcode 8.0、Swift 3.1,目标是iOS 10.0

z0qdvdin

z0qdvdin1#

这当然是可能的。你正在处理一个时间问题。你需要在viewWillAppear之前设置委托。不幸的是,没有方便的视图生命周期函数来插入赋值,所以我这样做了。
在你的PopoverViewController类中,在一个overriden getter中分配委托。如果你愿意,你可以使分配成为有条件的。这会创建一个永久的关系,这样其他代码就不会通过分配委托来“覆盖”它。

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

px9o7tmv2#

正如@allenh所正确观察到的,您需要在viewWillAppear之前设置delgate,他提供了一个聪明的解决方案,通过覆盖popoverPresentationController getter来设置委托。
您也可以在设置modalPresentationStyle和显示弹出窗口之间,在showPopover()函数中将代理设置为弹出窗口本身:

let vc = storyboard.instantiateViewController(withIdentifier: Lets.popoverStoryboardID )
vc.modalPresentationStyle = .popover
vc.popoverPresentationController?.delegate = vc
present(vc, animated: true, completion: nil)

相关问题