如何以编程方式触发 UIContextMenuInteraction 上下文菜单?
How to trigger UIContextMenuInteraction context menu programmatically?
我在 UINavigationController 中的 UIViewController 中将 UIButton 设置为 rightBarButtonItem,并为其关联了一个 iOS13 上下文菜单。
长按按钮会按预期显示上下文菜单。
有没有一种方法也可以通过点击按钮来显示上下文菜单(例如,通过为 .touchUpInside 事件添加目标)?
button/barButtonItem设置如下:
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "plus"), for: .normal)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.rightBarButtonItem = barButton
let interaction = UIContextMenuInteraction(delegate: self)
button.addInteraction(interaction)
上下文菜单定义如下:
extension ViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { suggestedActions in
let importAction = UIAction(title: "Import", image: UIImage(systemName: "folder")) { action in }
let createAction = UIAction(title: "Create", image: UIImage(systemName: "square.and.pencil")) { action in }
return UIMenu(title: "", children: [importAction, createAction])
}
}
}
根据设计,当出现适当的手势(用力触摸或长按)时,系统会自动显示上下文菜单。你不能手动显示它。
来自docs:
A context menu interaction object tracks Force Touch gestures on devices that support 3D Touch, and long-press gestures on devices that don't support it.
UIKit manages all menu-related interactions and reports the selected action, if any, back to your app.
更新:
尽管在 iOS14 中仍然无法手动显示上下文菜单,但现在可以将我们为上下文菜单创建的 UIMenu
显示为 pull-down menu. Check iOS 14.
iOS 14
iOS 14(第一个 Beta)现在支持所需的功能。使用以下代码点击 UIBarButtonItem 将立即显示菜单(同时避免调用 UIContextMenuInteraction 导致的背景模糊):
override func viewDidLoad() {
super.viewDidLoad()
let importAction = UIAction(title: "Import", image: UIImage(systemName: "folder")) { action in }
let createAction = UIAction(title: "Create", image: UIImage(systemName: "square.and.pencil")) { action in }
let menuBarButton = UIBarButtonItem(
title: "Add",
image: UIImage(systemName:"plus"),
primaryAction: nil,
menu: UIMenu(title: "", children: [importAction, createAction])
)
self.navigationItem.rightBarButtonItem = menuBarButton
}
该功能是通过 而不是 提供 primaryAction
。
您可以使用 UIButton 实现相同的效果。在这种情况下,您需要设置
button.showsMenuAsPrimaryAction = true
UIButton 的完整代码如下所示:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "plus"), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
let importAction = UIAction(title: "Import", image: UIImage(systemName: "folder")) { action in }
let createAction = UIAction(title: "Create", image: UIImage(systemName: "square.and.pencil")) { action in }
let items = [importAction, createAction]
button.menu = UIMenu(title: "Add", children: items)
button.showsMenuAsPrimaryAction = true
}
使用私有 API 可以完成这项工作。
@objc
func buttonTapped() {
// _presentMenuAtLocation:
guard let interaction = imageView.interactions.first,
let data = Data(base64Encoded: "X3ByZXNlbnRNZW51QXRMb2NhdGlvbjo="),
let str = String(data: data, encoding: .utf8)
else {
return
}
let selector = NSSelectorFromString(str)
guard interaction.responds(to: selector) else {
return
}
interaction.perform(selector, with: CGPoint.zero)
}
我在 UINavigationController 中的 UIViewController 中将 UIButton 设置为 rightBarButtonItem,并为其关联了一个 iOS13 上下文菜单。
长按按钮会按预期显示上下文菜单。
有没有一种方法也可以通过点击按钮来显示上下文菜单(例如,通过为 .touchUpInside 事件添加目标)?
button/barButtonItem设置如下:
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "plus"), for: .normal)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.rightBarButtonItem = barButton
let interaction = UIContextMenuInteraction(delegate: self)
button.addInteraction(interaction)
上下文菜单定义如下:
extension ViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { suggestedActions in
let importAction = UIAction(title: "Import", image: UIImage(systemName: "folder")) { action in }
let createAction = UIAction(title: "Create", image: UIImage(systemName: "square.and.pencil")) { action in }
return UIMenu(title: "", children: [importAction, createAction])
}
}
}
根据设计,当出现适当的手势(用力触摸或长按)时,系统会自动显示上下文菜单。你不能手动显示它。
来自docs:
A context menu interaction object tracks Force Touch gestures on devices that support 3D Touch, and long-press gestures on devices that don't support it.
UIKit manages all menu-related interactions and reports the selected action, if any, back to your app.
更新:
尽管在 iOS14 中仍然无法手动显示上下文菜单,但现在可以将我们为上下文菜单创建的 UIMenu
显示为 pull-down menu. Check
iOS 14
iOS 14(第一个 Beta)现在支持所需的功能。使用以下代码点击 UIBarButtonItem 将立即显示菜单(同时避免调用 UIContextMenuInteraction 导致的背景模糊):
override func viewDidLoad() {
super.viewDidLoad()
let importAction = UIAction(title: "Import", image: UIImage(systemName: "folder")) { action in }
let createAction = UIAction(title: "Create", image: UIImage(systemName: "square.and.pencil")) { action in }
let menuBarButton = UIBarButtonItem(
title: "Add",
image: UIImage(systemName:"plus"),
primaryAction: nil,
menu: UIMenu(title: "", children: [importAction, createAction])
)
self.navigationItem.rightBarButtonItem = menuBarButton
}
该功能是通过 而不是 提供 primaryAction
。
您可以使用 UIButton 实现相同的效果。在这种情况下,您需要设置
button.showsMenuAsPrimaryAction = true
UIButton 的完整代码如下所示:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "plus"), for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
let importAction = UIAction(title: "Import", image: UIImage(systemName: "folder")) { action in }
let createAction = UIAction(title: "Create", image: UIImage(systemName: "square.and.pencil")) { action in }
let items = [importAction, createAction]
button.menu = UIMenu(title: "Add", children: items)
button.showsMenuAsPrimaryAction = true
}
使用私有 API 可以完成这项工作。
@objc
func buttonTapped() {
// _presentMenuAtLocation:
guard let interaction = imageView.interactions.first,
let data = Data(base64Encoded: "X3ByZXNlbnRNZW51QXRMb2NhdGlvbjo="),
let str = String(data: data, encoding: .utf8)
else {
return
}
let selector = NSSelectorFromString(str)
guard interaction.responds(to: selector) else {
return
}
interaction.perform(selector, with: CGPoint.zero)
}