9

我正在尝试为我的应用程序中的每个视图创建一个自定义菜单,但是在视图控制器中似乎没有调用 buildMenu。这是一个例子:

在我的 AppDelegate 中,使用了此代码,它按预期 100% 工作。

override func buildMenu(with builder: UIMenuBuilder) {

    print("Updating menu from AppDelegate")

    super.buildMenu(with: builder)

    let command = UIKeyCommand(
        input: "W",
        modifierFlags: [.command],
        action: #selector(self.helloWorld(_:))
    )
    command.title = "Hello"

    builder.insertChild(UIMenu(
        __title: "World",
        image: nil,
        identifier: UIMenu.Identifier(rawValue: "com.hw.hello"),
        options: [],
        children: [command]
    ), atEndOfMenu: .file)
}

@objc private func helloWorld(_ sender: AppDelegate) {

    print("Hello world")
}

但是,我需要根据用户在应用程序中的位置更改菜单中可用的选项,因此我尝试在 UIViewController 中执行此操作:

override func viewDidAppear(_ animated:Bool){
  // Tried all of these to see if any work
    UIMenuSystem.main.setNeedsRebuild()
    UIMenuSystem.context.setNeedsRebuild()
    UIMenuSystem.main.setNeedsRevalidate()
    UIMenuSystem.context.setNeedsRevalidate() 
}

然后再次..

// This is never called
override func buildMenu(with builder: UIMenuBuilder) {

    print("Updating menu in View Controller")
}

但是 UIViewController 中的 buildMenu 永远不会被调用:(

如果这是预期的行为或是否有任何解决方法,有什么想法吗?

4

2 回答 2

17

对于菜单,系统只参考UIApplicationUIApplicationDelegate,因为主菜单可以在没有任何窗口的情况下存在,因此没有任何UIViewController层次结构。UIViewController这就是为什么主菜单不会调用您的覆盖。

对于上下文菜单,系统确实会从视图开始咨询完整的响应者链。

如果您需要根据上下文更新主菜单命令:

  • 您可以离开buildMenu(with:)UIApplicationDelegate安排代表弄清楚何时以及发生了什么变化,并在发生变化UIMenuSystem.main.setNeedsRebuild()时致电,或者
  • buildMyMenu(with:)您可以在子类中定义一个私有方法UIViewController,并安排buildMenu(with:)inUIApplicationDelegate调用它,或者
  • 您可以在 中构建一个静态菜单buildMenu,并依靠您的覆盖canPerformAction(_:withSender:)validate(_:)启用或禁用甚至隐藏特定命令,例如通过更新覆盖attributes中的属性validate(_:)
于 2019-08-06T20:25:38.450 回答
1

这是预期的行为。引用文档

因为菜单可以在没有窗口或视图层次结构的情况下存在,系统咨询UIApplicationUIApplicationDelegate构建应用程序的菜单栏。

同一个文档页面解释了如何从视图控制器调整菜单命令,还有一个很棒的示例项目,所以一定要检查它。

于 2020-08-09T19:44:27.270 回答