NSStoryboardSegue示例代码(Yosemite Storyboard)

Zel*_*lko 4 macos objective-c swift osx-yosemite

OS X Yosemite推出了NSStoryboardSegue

"故事板segue指定故事板中两个场景之间的过渡或遏制关系......"


更新:

•如果我尝试在带有Yosemite的Storyboard中使用NSStoryboardSegue子类,则它会与SIGABRT崩溃.

•如果我忽略segues,并使用指定的自定义动画师手动呈现视图控制器以进行演示和解雇,

func presentViewController(_ viewController: NSViewController,
                  animator animator: NSViewControllerPresentationAnimator)
Run Code Online (Sandbox Code Playgroud)

它按预期工作.


这篇文章提供了额外的见解:在OS X Yosemite中为ViewController定制动画

使用它作为参考,这是我到目前为止的尝试:

class FadeSegue: NSStoryboardSegue {

    override func perform() {
        super.perform()
        sourceController.presentViewController(destinationController as NSViewController,
            animator: FadeTransitionAnimator())
    }
}


class FadeTransitionAnimator: NSObject, NSViewControllerPresentationAnimator {

    func animatePresentationOfViewController(toViewController: NSViewController, fromViewController: NSViewController) {

        toViewController.view.wantsLayer = true
        toViewController.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay
        toViewController.view.alphaValue = 0
        fromViewController.view.addSubview(toViewController.view)
        toViewController.view.frame = fromViewController.view.frame

        NSAnimationContext.runAnimationGroup({ context in
            context.duration = 2
            toViewController.view.animator().alphaValue = 1
            }, completionHandler: nil)
    }

    func animateDismissalOfViewController(viewController: NSViewController, fromViewController: NSViewController) {

        viewController.view.wantsLayer = true
        viewController.view.layerContentsRedrawPolicy = .OnSetNeedsDisplay

        NSAnimationContext.runAnimationGroup({ (context) -> Void in
            context.duration = 2
            viewController.view.animator().alphaValue = 0
            }, completionHandler: {
                viewController.view.removeFromSuperview()
        })
    }

}
Run Code Online (Sandbox Code Playgroud)

fou*_*dry 7

问题似乎与Swift'NSStoryboardSegue的子类化'有关.如果使用Objective-C实现相同的功能,一切都按预期工作.这个问题特别针对你的FadeSeque班级.动画对象在Objective-C Swift 中都可以正常工作.

所以这:

class FadeSegue: NSStoryboardSegue {
    override func perform() {
    super.perform()
    sourceController.presentViewController(destinationController as NSViewController,
        animator: FadeTransitionAnimator())
    }
} 
Run Code Online (Sandbox Code Playgroud)

如果作为Objective-C类提供,将会起作用:

@interface MyCustomSegue : NSStoryboardSegue
@end

@implementation FadeSegue

- (void)perform {
   id animator = [[FadeTransitionAnimator alloc] init];
    [self.sourceController presentViewController:self.destinationController
                                        animator:animator];
   }
   @end
Run Code Online (Sandbox Code Playgroud)

(我觉得你不需要打电话super)

由于这似乎没有在任何地方记录,我在github上做了一个小项目来演示:

  • NSStoryboardSegue在同一个Storyboard中从一个NSViewController转换到另一个NSViewController
  • NSViewController目前:在使用Storyboard Segue的 情况下实现对单独的基于Xib的NSViewController的相同影响的方法presentViewController:asPopoverRelativeToRect:ofView:preferredEdge:behavior:
    presentViewControllerAsSheet:
    presentViewControllerAsModalWindow:
    presentViewController:animator:
  • Objective-C和Swift中的animator和segue对象

在此输入图像描述

编辑

好的,我已经找到了EXC_BAD_ACCESS问题.查看堆栈跟踪,它似乎与(Objective-C)NSString到(Swift)字符串转换有关.

在此输入图像描述

这让想进一步了解identifier的财产NSStoryboardSegue.这在Storyboard中设置segue时使用,在代码中创建的自定义segue中不太有用.但是,事实证明,如果您将故事板中的标识符设置为任何字符串值,甚至是"",则崩溃将消失.

identifier属性是Objective-C中的NSString*

@property(readonly, copy) NSString *identifier
Run Code Online (Sandbox Code Playgroud)

和Swift中的可选String:

var identifier: String? { get }
Run Code Online (Sandbox Code Playgroud)

请注意只读状态.您只能在初始化对象时设置标识符.

NSStoryboardSegue在Objective-C中,指示符初始化器看起来像这样:

- (instancetype)initWithIdentifier:(NSString *)identifier
                            source:(id)sourceController
                       destination:(id)destinationController
Run Code Online (Sandbox Code Playgroud)

在斯威夫特:

init(identifier identifier: String,
         source sourceController: AnyObject,
    destination destinationController: AnyObject)
Run Code Online (Sandbox Code Playgroud)

请注意Swift初始化程序中的非可选要求.其中存在问题和崩溃.如果您没有在故事板中故意设置标识符,则将使用标识符的nil值调用Custom segue的指定初始化程序.在Objective-C中不是问题,但对Swift来说是坏消息.

快速解决方案是确保在Storyboard中设置标识符字符串.对于更强大的解决方案,事实证明您可以覆盖自定义子类中的指定初始化程序以拦截零值字符串.然后你可以在传递给super的指定初始化器之前用默认值填充它:

override init(identifier: String?, 
              source sourceController: AnyObject,
              destination destinationController: AnyObject) {
        var myIdentifier : String
        if identifier == nil {
            myIdentifier = ""
        } else {
            myIdentifier = identifier!
        }
    super.init(identifier: myIdentifier, 
                source: sourceController, 
                destination: destinationController)
}
Run Code Online (Sandbox Code Playgroud)

我已更新示例项目以反映此解决方案