3

总体目标:在 macOS 上使用自定义故事板 segue

手头的问题是响应者链。据苹果称:

此外,在 macOS 10.10 及更高版本中,视图控制器参与响应者链。NSViewController

如果我在 macOS 故事板中使用标准 segue,则目标视图控制器的行为符合预期——焦点、等效键、响应者链等。

但是,如果我使用自定义 segue,则目标视图控制器的行为不符合预期:( 具体来说,关键等效项神秘地无法工作 - 但是,在测试中,来自视图控制器的按钮上的关键等效项继续工作(这不是t 有帮助/需要)

在 macOS 10.12 上,我正在使用以下自定义 segue……我做错了什么?

class PushSegue: NSStoryboardSegue {

override func perform() {
    (sourceController as AnyObject).presentViewController(destinationController as! NSViewController, animator: PushAnimator())
}
}


class PushAnimator:  NSObject, NSViewControllerPresentationAnimator  {

func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) {
    viewController.view.wantsLayer = true
    viewController.view.frame = CGRect(x: fromViewController.view.frame.size.width, y: 0,
                                       width: fromViewController.view.frame.size.width, height: fromViewController.view.frame.size.height)
    fromViewController.addChildViewController(viewController)
    fromViewController.view.addSubview(viewController.view)

    let futureFrame = CGRect(x: 0, y: 0, width: viewController.view.frame.size.width,
                             height: viewController.view.frame.size.height)

    NSAnimationContext.runAnimationGroup({ context in
        context.duration = 0.75
        viewController.view.animator().frame = futureFrame

    }, completionHandler:nil)
}

func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) {
    let futureFrame = CGRect(x: viewController.view.frame.size.width, y: 0,
                             width: viewController.view.frame.size.width, height: viewController.view.frame.size.height)

    NSAnimationContext.runAnimationGroup({ context in
        context.duration = 0.75
        context.completionHandler = {
            viewController.view.removeFromSuperview()
            viewController.removeFromParentViewController()
        }

        viewController.view.animator().frame = futureFrame
    }, completionHandler: nil)
    
}
}
4

1 回答 1

8

根据我的理解,你的问题有四个部分:

  1. 如何使用自定义 segue 类
  2. KeyEquivalents的问题
  3. 响应者链的问题
  4. 焦点问题

解决方案演示

我有以下示例与您的自定义 segue 类关键等效示例、响应者链示例和焦点示例(假设您的意思是 TextField 焦点)一起正常运行。

正如您在下面的 gif 中看到的,您可以单击Segue按钮以使用您的PushSeguesegue 进行转换。然后单击“关闭”按钮返回。左右箭头分别是SegueDismiss按钮的等效键。响应者链成功地将数据从SheetController(红屏)传递到MainViewController(灰屏)。此外,文本字段在 segue 时正确获得焦点。我将更详细地解释每个功能。

在此处输入图像描述

PushSegue

我采用了PushAnimator您发布的子类,并在视图中添加了一个红色背景,以便我可以直观地看到它。我通过在您的类的animatePresentation方法中添加以下行来做到这一点:PushAnimator

viewController.view.layer?.backgroundColor = CGColor.init(red: 1, green: 0, blue: 0, alpha: 1)

关键等价物

Segue按钮被分配了 keyEquivalent ofNSRightArrowFunctionKey并且Dismiss按钮被分配了NSLeftArrowFunctionKey。您可以点击左右箭头键在两个视图之间切换。为了设置右箭头,我在MainViewController viewDidLoad()函数中添加了以下内容:

let array = [unichar(NSRightArrowFunctionKey)]
mainViewSegueButton.keyEquivalent = String(utf16CodeUnits: array, count: 1)

为了设置左箭头,我在SheetController viewDidLoad()函数中添加了以下内容:

let array = [unichar(NSLeftArrowFunctionKey)]
dismissButton.keyEquivalent = String(utf16CodeUnits: array, count: 1)

响应者链

由于您没有描述您在响应者链中遇到的具体问题,因此我只是实施了一个简单的测试以查看它是否有效。我将设置SheetController'sdismissButton的 nextResponder MainViewController。我在SheetController's中有以下内容viewDidLoad()

// SheetController viewDidLoad() 
// Set Accessibility Label
dismissButton.setAccessibilityLabel("DismissButton")

// Set button target and action        
dismissButton.target = nil
dismissButton.action = #selector(MainViewController.dismissAction(_:))
        
// Set nextResponder
dismissButton.nextResponder = self.parent

为了解释上面的内容:我首先设置了dismissButton一个可访问性标签,以便MainViewController以后可以识别按钮。将按钮的目标设置为 nil 意味着它将查看其 nextResponder 以处理它检测到的任何事件。我将按钮的操作设置为dismissAction方法,该方法在MainViewController. 最后,我将dismissButton's nextResponder 设置为MainViewController

回到中MainViewController,我设置了dismissAction下面的方法。它只是增加一个计数器变量并将该计数器与按钮的accessibilityLabel(与我们之前设置的访问标签相同)一起显示到textField。最后一行取消了SheetController.

// MainViewController
func dismissAction(_ sender: AnyObject) {
    counter += 1
    let buttonAccessLabel = (sender as! NSButton).accessibilityLabel()
    helloWorldTextField.stringValue = "Action #" + counter.description + " from: " + buttonAccessLabel!
    self.dismissViewController(self.presentedViewControllers!.first!)
}

重点

为此,我假设您指的是 textField 焦点。在SheetController,我的sheetFocusTextField重点是viewDidAppear

override func viewDidAppear() {
    super.viewDidAppear()
    sheetFocusTextField.becomeFirstResponder()
}

MainViewController,我mainFocusTextField专注于dismissAction方法:

mainFocusTextField.becomeFirstResponder()

Github 链接

https://github.com/starkindustries/mac-os-segue-test

参考

于 2017-04-19T23:51:53.457 回答