class Coordinator: NSObject, UIContextMenuInteractionDelegate, ContextMenuManagerDelegate {
var container: ContextMenuContainer
var auxiliaryContent: AuxiliaryContent
var menuItems: () -> [UIMenuElement]
init(container: ContextMenuContainer) {
self.container = container
self.auxiliaryContent = container.auxiliaryContent
self.menuItems = container.menuItems
super.init()
}
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint
) -> UIContextMenuConfiguration? {
container.viewModel.contextMenuManager?.notifyOnContextMenuInteraction(
interaction,
configurationForMenuAtLocation: location
)
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { [weak self] _ in
UIMenu(title: "", children: self?.menuItems() ?? [])
}
}
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
willDisplayMenuFor configuration: UIContextMenuConfiguration,
animator: UIContextMenuInteractionAnimating?
) {
container.viewModel.contextMenuManager?.notifyOnContextMenuInteraction(
interaction,
willDisplayMenuFor: configuration,
animator: animator
)
}
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
willEndFor configuration: UIContextMenuConfiguration,
animator: UIContextMenuInteractionAnimating?
) {
container.viewModel.contextMenuManager?.notifyOnContextMenuInteraction(
interaction,
willEndFor: configuration,
animator: animator
)
}
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
previewForHighlightingMenuWithConfiguration configuration: UIContextMenuConfiguration
) -> UITargetedPreview? {
guard let targetView = interaction.view else { return nil }
let bubbleWithTail = BubbleWithTailPath()
let customPath = bubbleWithTail.path(in: targetView.bounds)
let parameters = UIPreviewParameters()
parameters.visiblePath = customPath
return UITargetedPreview(
view: targetView,
parameters: parameters
)
}
func onRequestMenuAuxiliaryPreview(sender: ContextMenuManager) -> UIView? {
let hostingController = UIHostingController(rootView: auxiliaryContent)
hostingController.view.backgroundColor = .clear
return hostingController.view
}
}
i am trying to recreate apple's iMessage tapback reaction context menu. i have figured out how to attach an auxiliary view to the view with the menu, however the menu itself varies in position. if i bring up the context menu on a view below half the screen height, the menu appears above the view. else, it appears below. i need it to always be below.