使用拆分视图控制器将菜单项显示为灰色-Catalyst

时间:2019-10-13 13:23:19

标签: ios swift maccatalyst

我正在努力使用Catalyst将我的iPad应用程序引入Mac。我的应用程序使用拆分视图控制器。主视图控制器具有两行可以点击,用户可以使用它们拍摄照片或从相机胶卷中选择照片。 我试图为每个操作添加两个带有键盘快捷键的菜单项。

按照WWDC视频中的步骤添加菜单项后,该菜单项在应用程序首次启动时显示为灰色。下面的屏幕快照显示了首次启动的应用程序,并且“拍摄照片”和“从相机胶卷选择”均呈灰色。 Grayed out menu items

但是,如果我切换/点击主视图控制器中的任何项目,则菜单项将启用并按预期工作。选择菜单项后,它又变回了灰色,我需要在主视图控制器中切换/点击一个项以再次启用它们。 enabled menu items

我不知道为什么这些项目会变灰。我认为这可能与拆分视图控制器有关,但无法找出任何答案。

我用来添加菜单项的代码非常简单。我在拍摄照片并从相机胶卷中选择的方法中添加了@IBAction。我将带有两个新的“内联菜单”项的“主菜单”添加到我的情节提要文件中,并将它们分别连接到方法。

3 个答案:

答案 0 :(得分:0)

您尝试关闭菜单的“自动启用项目”。 如果这样做无济于事,或者您想控制激活,我将按照Apple here的文档进行操作,或在视图控制器中尝试以下类似操作。

 override func validate(_ command: UICommand) {

      switch command.action {
      case #selector(doSomething):

          command.title = "Change the title"
          command.attributes = [.disabled]
            // command.attributes = []

        default:
        break
      }
    }

enter image description here

答案 1 :(得分:0)

我对这种方法并不完全满意,但这就是我一直在努力解决的问题...

主视图控制器的viewDidAppear()包括tableView.becomeFirstResponder()

加上,详细信息控制器将覆盖next以指向主视图控制器:

override var next: UIResponder? { return masterViewController }

加上,详细信息视图控制器的viewDidAppear()还必须包括:

someSuitableSubview.becomeFirstResponder()

现在,我的Mac Catalyst菜单的行为基本上符合预期!

是否有更好的策略将这两个视图都保留在响应者链中,只要它们被显示(并且它们的窗口位于最前面)?

答案 2 :(得分:0)

我在 Catalyst 应用中遇到了一个可能相关的问题。

我正在使用 menu 菜单构建器方法,但我发现该应用程序将请求一个视图控制器的菜单,但尝试针对另一个视图控制器对其进行验证。我认为这是因为我有两个视图控制器负责同一屏幕的各个部分。

我使用的解决方法是处理对另一个视图控制器中一个视图控制器菜单项的查询。例如,假设您有共享屏幕的控制器,称为

  • MainVC
  • PlayViewController

该应用程序将调用 MainVC 的菜单生成器,但您希望有一些调用 PlaybackVC 方法的热键。例如,您可以使用一个调用 PlayViewController.nextClip() 的项目填充 Playback 菜单。

@available(iOS 13.0, *)
class func playbackMenu() -> UIMenu
{
let prevCmd =
    UIKeyCommand(title: "Previous clip",
                 image: nil,
                 action: #selector(PlayViewController.cmdPrevClip(_:)),
                 input: UIKeyCommand.inputLeftArrow,
                 modifierFlags: .control,
                 propertyList: nil)

let nextCmd =
    UIKeyCommand(title: "Next clip",
                 image: nil,
                 action: #selector(PlayViewController.cmdNextClip(_:)),
                 input: UIKeyCommand.inputRightArrow,
                 modifierFlags: .control,
                 propertyList: nil)

let loopCmd =
    UIKeyCommand(title: "Loop",
                 image: nil,
                 action: #selector(PlayViewController.cmdToggleLoopClip(_:)),
                 input: "L",
                 modifierFlags: .control,
                 propertyList: nil)
let theMenu =
    UIMenu(title: "Playback",
           image: nil,
           identifier: UIMenu.Identifier("com.atomos.AtomRemoteMenus.playbackMenu"),
           options: .destructive,
           children: [prevCmd, nextCmd, loopCmd])

return theMenu
}

稍后,当操作系统要求 MainVC 验证播放菜单中的项目时,MainVC 的 canPerformAction() 方法需要像这样处理它:

else if action == #selector(PlayViewController.cmdNextClip(_:))
{
    if m_playController != nil
    {
        return m_playController!.canPerformAction(#selector(PlayViewController.cmdNextClip(_:)), withSender: sender)
    }
    else
    {
        return false
    }
}

所以是的,我在 PlayViewController 中有一个多余的 canPerformAction 方法,因为我不知道它是否有朝一日会被调用。

您可能会想,嘿,我只会在 MainVC 中创建存根方法,并在 Playback 菜单中调用这些方法,然后依次调用 PlayViewController 的方法。不,因为每个菜单项的命令都针对它认为活动视图控制器在任何给定点上的内容......在我的情况下这不是 MainVC。