2

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

按照 WWDC 视频中的步骤添加菜单项后,应用程序首次启动时菜单项将显示为灰色。下面是显示应用程序首次启动的屏幕截图,拍照和从相机胶卷中选择都是灰色的。 变灰的菜单项

但是,如果我切换/点击主视图控制器中的任何项目,菜单项就会启用并按预期工作。一旦我选择了一个菜单项,它就会变灰,我需要在主视图控制器中切换/点击一个项目以使它们再次启用。 启用的菜单项

我无法弄清楚为什么这些项目是灰色的。我认为它可能与拆分视图控制器有关,但无法解决任何问题。

我用来添加菜单项的代码非常简单。我添加@IBAction了拍摄照片并从相机胶卷中选择的方法。我在 Storyboard 文件中添加了一个主菜单,其中包含两个新的内联菜单项,并将每个项连接到方法。

4

3 回答 3

0

更新:我把它弄混了。这仅适用于 macOS,但不适用于 Catalyst 应用程序!!!。

对于 Catalyst,最好的方法是使用菜单构建器和相关功能。

------ 如果它是关于 Catalyst 的,请忽略它 --------

您是否尝试关闭菜单的“自动启用项目”。如果这无济于事,或者您想控制激活,我将遵循 Apple此处的文档或尝试在您的视图控制器中使用类似下面的内容。

 override func validate(_ command: UICommand) {

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

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

        default:
        break
      }
    }

在此处输入图像描述

于 2019-10-15T17:28:19.417 回答
0

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

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

另外,细节控制器覆盖next指向主视图控制器:

override var next: UIResponder? { return masterViewController }

另外,详细视图控制器viewDidAppear()还必须包括:

someSuitableSubview.becomeFirstResponder()

现在,我的 mac Catalyst 菜单的行为大多符合预期!

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

于 2020-05-29T11:16:16.750 回答
0

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

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

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

  • 主VC
  • 播放视图控制器

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

@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验证 Playback 菜单中的项目时,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。

于 2021-03-10T04:25:11.417 回答