MacOS开发03-窗口跳转

1,488 阅读3分钟

前言

如你所见,大部分软件都不止有一个窗口,一个完整的软件一般会有多个窗口组成,每个窗口用于不同的功能,那如何来做窗口跳转呢,下面是几种方式。

创建项目

创建StoryBoard项目,命名为:03.window。

image.png

展示窗口的几种类型

  1. 直接showWindow一个窗口
  2. 模态框
  3. sheet
  4. popover
  5. 自定义动画

1. 直接showWindow一个窗口

打开StoryBoard,拖入一个按钮,双击修改title为:showWindow,关联点击事件:showWindowAction(如何创建按钮及关联事件见MacOS开发02-窗口对象)

image.png

在StoryBoard里拖入一个NSWindowController,修改StoryBoard ID为:FirstWindow,并在这个窗口的View中拖入一个Wrapping Label,修改内容为:First Window。

image.png

打开ViewController,修改showWindowAction函数的内容为:

@IBAction func showWindowAction(_ sender: NSButton) {
        let windowController = storyboard?.instantiateController(withIdentifier: "FirstWindow") as? NSWindowController
        windowController?.showWindow(self)
        windowController?.window?.center()
}

启动可见效果。

2. 模态框

打开StoryBoard,在ViewController中拖入一个按钮,命名为:Modal Window,关联事件函数:tapModalAction, 添加内容为:

    @IBAction func tapModalAction(_ sender: Any) {
        let windowController = storyboard?.instantiateController(withIdentifier: "FirstWindow") as! NSWindowController
        presentAsModalWindow(windowController.contentViewController!)
    }

3. sheet

打开StoryBoard,在ViewController中拖入一个按钮,命名为:Sheet Window,关联事件函数:tapSheetAction, 添加内容为:

    @IBAction func tapModalAction(_ sender: Any) {
        let windowController = storyboard?.instantiateController(withIdentifier: "FirstWindow") as! NSWindowController
        presentAsSheet(windowController.contentViewController!)
    }

打开新窗口后发现没法关闭该窗口,那么需要在新窗口中添加一个关闭按钮,并关联点击事件:tapClose,发现新的ViewController没有自定义的类,无法关联到我们自己的事件函数,这时需要新创建一个Cocoa class,命名为:FirstViewController,继承:NSViewController,并修改自定义类型为该类。

image.png

修改函数内容为:

    @IBAction func tapClose(_ sender: NSButton) {
        dismiss(self)
    }

4. popover

拖入一个按钮,命名为:Popover Window,关联事件函数:tapPopoverAction, 添加内容为:

    @IBAction func tapPopoverAction(_ sender: NSButton) {
        let windowController = storyboard?.instantiateController(withIdentifier: "FirstWindow") as! NSWindowController
        present(windowController.contentViewController!, asPopoverRelativeTo: sender.frame, of: self.view, preferredEdge: .maxX, behavior: .transient)
    }

5. 自定义动画

自定义动画方式需要创建一个NSViewControllerPresentationAnimator的实现类,来具体实现如何做动画。

class FirstCustomAnimator: NSObject, NSViewControllerPresentationAnimator{
    func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) {
        let bottomVC = fromViewController
        let topVC = viewController
        
        topVC.view.wantsLayer = true
        topVC.view.alphaValue = 0
        
        bottomVC.view.addSubview(topVC.view)
        topVC.view.layer?.backgroundColor = NSColor.gray.cgColor
        
        NSAnimationContext.runAnimationGroup { context in
            context.duration = 0.5
            topVC.view.animator().alphaValue = 1
        }
    }
    
    func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) {
        let topVC = viewController
        
        NSAnimationContext.runAnimationGroup { context in
            context.duration = 0.5
            topVC.view.animator().alphaValue = 0
        } completionHandler: {
            topVC.view.removeFromSuperview()
        }
    }
}


然后按照惯例,拖入一个按钮,命名为:Custom Animation Window,关联事件函数:tapAnimationAction, 添加内容为:

    @IBAction func tapAnimationAction(_ sender: NSButton) {
        let windowController = storyboard?.instantiateController(withIdentifier: "FirstWindow") as! NSWindowController

        let animator = FirstCustomAnimator()
        
        self.present(windowController.contentViewController!, animator: animator)
    }

StoryBoard的方式跳转窗口

刚刚介绍了使用代码的方式跳转,StoryBoard还为我们提供了更加方便快捷的方式跳转,那就是Segue。

我们在ViewController里先拖入一个Box, 修改标题为:代码跳转,然后将刚刚添加的按钮都拖入进来,再添加另外一个Box,修改标题为:Segue 跳转,再新增5个按钮。

image.png

然后按住Ctrl+ShowWindow按钮拖动到下面的FirstViewController中,并选择Show,That's it.

image.png

以此将Modal Window、sheet、popover、custom都按照这个方式添加Segue。 其中针对Custom类型的Segue,需要实现一个NSStoryboardSegue的子类,然后修改自定义class为该类

class CustomSegue: NSStoryboardSegue{
    override func perform() {
        let source = self.sourceController as! NSViewController
        let destination = self.destinationController as! NSViewController
        let animator = FirstCustomAnimator()
        source.present(destination, animator: animator)
    }
}

image.png

页面跳转传参

选中Show Window的那个Segue,添加Identifier: ShowWindowIdentifier, 然后将FirstViewController中新增的Warrping Label添加一个outlet。 重写ViewController中的prepare(for segue: NSStoryboardSegue, sender: Any?)方法,添加如下代码: image.png

ViewController: 
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
        print("segue:\(segue.identifier)")
        if segue.identifier == "ShowWindowIdentifier"{
            if let firstVC = segue.destinationController as? FirstViewController {
                firstVC.representedObject = "Hello, This is Show Window!"
            }
        }
}
    

representedObject是预留的一个用于传参的Any类型的变量,在FirstViewController的viewDidLoad回调中添加如下代码:

FirstViewController:
 override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        
        if let stringText = self.representedObject as? String {
            self.label.stringValue = stringText
        }
    }

每次通过Segue跳转都会走这个函数,而针对每个跳转可以修改标识名称:identifier,根据不同的跳转,转换为不同的ViewController,从而传递不同的参数。 课后作业:试着将几种不同类型的跳转改为不同的ViewController,传递不同的参数,展示不同的内容。

最后

好了,以上就是今天的所有内容,如果对你帮助还请帮忙点个赞,希望我们能在下篇文章相见!