Наконец-то добрались до сути вопроса и нашли разумное решение.
В приложении, которое я разрабатываю, есть несколько всплывающих окон, которые требуются на разных этапах, чтобы обеспечить их закрытие по мере необходимости. Я создал службу, которая управляет каждым поповером, вот пример:
class PopoverService: NSObject {
enum PopoverType {
case subscription, edit
}
//================================================================================
// MARK: - Properties
//================================================================================
private var dismissingPopover = false
private lazy var currentPopover: NSPopover = {
let popover = NSPopover()
popover.delegate = self
return popover
}()
private var nextPopoverType: PopoverType?
private var currentView: NSView!
public static var delegate: PopoverServiceDelegate?
//================================================================================
// MARK: - Singleton
//================================================================================
static let shared = PopoverService()
//================================================================================
// MARK: - Helpers
//================================================================================
public static func increaseHeight(_ height: CGFloat) {
shared.currentPopover.contentSize.height = height
}
public static func isDisplayingType(_ type: PopoverType) -> Bool {
switch type {
case .edit:
return shared.currentPopover.contentViewController is EditEntryController
case .language:
return shared.currentPopover.contentViewController is CodeTypeController
default:
return false
}
}
public static func displayPopover(type: PopoverType, fromView view: NSView) {
shared.nextPopoverType = type
shared.currentView = view
switch type {
case .subscription:
displaySubscriptionPopoverFrom(view)
// Create functions to display your popovers
}
}
static func dismissPopover(clearUpcoming: Bool = true) {
if clearUpcoming {
shared.nextPopoverType = nil
}
shared.currentPopover.performClose(nil)
if shared.currentPopover.contentViewController == nil {
shared.dismissingPopover = false; return
}
}
}
extension PopoverService: NSPopoverDelegate {
func popoverDidClose(_ notification: Notification) {
currentPopover.contentViewController = nil
dismissingPopover = false
guard let nextPopoverType = nextPopoverType else { return }
PopoverService.displayPopover(
type: nextPopoverType,
fromView: currentView,
entry: currentEntry
)
}
}
Для обновления текущего поповера есть функция increaseHeight
, которая принимает и CGFloat
и обновляет текущую высоту поповеров.
В NSViewController переопределить viewDidLayout()
:
override func viewDidLayout() {
super.viewDidLayout()
let windowFrameHeight = view.window?.frame.size.height ?? 0
let contentHeight = scrollView.content.frame.height
let adjustment = contentHeight > windowFrameHeight ? windowFrameHeight : contentHeight
PopoverService.increaseHeight(adjustment)
if contentHeight > 0 && firstLayout {
if let documentView = scrollView.documentView {
documentView.scroll(NSPoint(x: 0, y: documentView.bounds.size.height))
}
}
}
scrollView нужно будет переместиться вверх, поэтому есть переменная firstLayout
, которую вы можете установить в true в viewDidAppear