Может ли UIViewController, представленный как поповер, быть его собственным делегатом popoverPresentationController?

В показанном ниже проекте есть InitialViewController это имеет одну кнопку с надписью "Показать поповер". При нажатии этой кнопки приложение должно представить второй контроллер вида (PopoverViewController) как поповер На втором контроллере представления есть надпись "Popover!".

изображение раскадровки

Это прекрасно работает, если InitialViewController заботится о создании экземпляров PopoverViewController, извлекая popoverPresentationController а затем установка popoverPresentationController's delegate к себе InitialViewController). Вы можете увидеть результат ниже:

приложение functiong при делегировании в InitialViewController

Однако для максимального повторного использования было бы здорово, если бы InitialViewController не нужно было ничего знать о том, как делегируется контроллер представления. Я думаю, что это должно быть возможно для PopoverViewController установить себя как popoverPresentationController's delegate, Я пробовал это либо в viewDidLoad или viewWillAppear функции PopoverViewController, Тем не менее PopoverViewController представлен модально в обоих случаях, как показано ниже:

Весь код содержится только в 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

    }
}

Код в провале 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

2 ответа

Решение

Это конечно возможно. Вы имеете дело с проблемой времени. Вы должны установить делегата до viewWillAppear, К сожалению, нет удобной функции просмотра жизненного цикла для вставки назначения, поэтому я сделал это вместо этого.

В вашем PopoverViewController класс, назначьте делегата в переопределенном получателе. Вы можете сделать назначение условным, если хотите. Это создает постоянную связь, поэтому другой кодовый код никогда не переопределяет делегат, назначая его.

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

Как правильно заметил @allenh, вам нужно установить delgate передviewWillAppear, и он предложил умное решение, установив делегата, переопределивpopoverPresentationControllerдобытчик.

Вы также можете установить делегата для самого всплывающего окна в вашемshowPopover()функция между настройкамиmodalPresentationStyleи представляя всплывающее окно:

      let vc = storyboard.instantiateViewController(withIdentifier: Lets.popoverStoryboardID )
vc.modalPresentationStyle = .popover
vc.popoverPresentationController?.delegate = vc
present(vc, animated: true, completion: nil)
Другие вопросы по тегам