1

I would like to present my UIMenu from UIButton when button is tapped. Because in the beginning I need to update children of UIMenu.

let menuButton: UIButton = {
    let button = UIButton()
    button.menu = UIMenu(title: "title")
    button.showsMenuAsPrimaryAction = true
    return button
}()

func setupView() {
    menuButton.rx.tap.bind {
        let action = UIAction(title: "title", image: nil, handler: { _ in })
        menuButton.menu.replacingChildren([action])
//            present menu, how?
    }.disposed(by: disposeBag)
}

Nothing happens here. My action for tap is registered with RxSwift. How can I do it to present the menu?

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358

2 Answers2

3

There is a need to add system .menuActionTriggered action:

let menuButton: UIButton = {
    let button = UIButton()
    button.menu = UIMenu(title: "")
    button.showsMenuAsPrimaryAction = true
    return button
}()

menuButton.addAction(UIAction(title: "") { _ in
    menuButton.menu = UIMenu(title: "newtitle", children: [])
    // this block is called BEFORE new menu appear on the screen, and anything may be modified before presentation
}, for: .menuActionTriggered)

replacingChildren([action]) return a copy of new UIMenu which need to be assigned to .menu property again.

halfer
  • 19,824
  • 17
  • 99
  • 186
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
0

I hope my answer will work for you. This is pretty easy in iOS 14 and above.

By default, the nature of UIMenu to launch is on Long Press.

To make it a single click to open UIMenu iOS 14 provides a single line of code.

 @IBAction func open(_ sender: UIButton) {
        if #available(iOS 14.0, *) {
            sender.menu = self.getContextMenu(data: "Copy this data")
            sender.showsMenuAsPrimaryAction = true
        } else {
            // Fallback on earlier versions
        }
    }

button.showsMenuAsPrimaryAction = true

To find the complete code got to my Github

Kumar Lav
  • 234
  • 1
  • 3
  • 9