Может ли UIViewController, представленный как поповер, быть его собственным делегатом popoverPresentationController?
В показанном ниже проекте есть InitialViewController
это имеет одну кнопку с надписью "Показать поповер". При нажатии этой кнопки приложение должно представить второй контроллер вида (PopoverViewController
) как поповер На втором контроллере представления есть надпись "Popover!".
Это прекрасно работает, если InitialViewController
заботится о создании экземпляров PopoverViewController
, извлекая popoverPresentationController
а затем установка popoverPresentationController's delegate
к себе 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)