OSX使用代码代替storyboard构建项目,并添加NSSplitView组件

2020/12/17 posted in  mac&ios

众所周知,storyboard能够加速界面开发,但在项目变大时,其会出现难以维护的窘境,这种情况下去storyboard就是必经之路了

创建案例项目

删除项目设置中引用的Main.storyboard

删除Main.storyboard文件,效果如下

创建main.swift文件作为项目入口

参考代码如下

import Cocoa

let delegate = AppDelegate()

NSApplication.shared.delegate = delegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

从AppDelegate.swift中删除NSApplicationMain注解

参考效果如下

在AppDelegate.swift中创建项目启动时进入的窗口(Window)文件

在AppDelegate.swift中创建一个属性来存放这个window

private var window: NSWindow?

applicationDidFinishLaunching中执行初始化代码如下

let styleMask: NSWindow.StyleMask = [
    .miniaturizable,
    .closable,
    .resizable,
    .titled,
]

window = NSWindow(
    contentRect: NSMakeRect(0, 0, 1400, 960),
    styleMask: styleMask,
    backing: .buffered,
    defer: false
)

window?.title = "A No Storyboard App"
window?.makeKeyAndOrderFront(nil)
window?.contentViewController = MainSplitViewController()

创建MainSplitViewController.swift作为窗口内的入口视图控制器

import Cocoa

class MainSplitViewController: NSSplitViewController {
    private let splitViewResorationIdentifier = "com.company.restorationId:mainSplitViewController1"

    lazy var vcA = ViewController(backgroundColor: .red)
    lazy var vcB = ViewController(backgroundColor: .green)
    lazy var vcC = ViewController(backgroundColor: .blue)

    override func viewDidLoad() {
        setupUI()
        setupLayout()
    }
}

extension MainSplitViewController {
    private func setupUI() {
        view.wantsLayer = true

        splitView.dividerStyle = .thin
        splitView.autosaveName = NSSplitView.AutosaveName(splitViewResorationIdentifier)
        splitView.identifier = NSUserInterfaceItemIdentifier(rawValue: splitViewResorationIdentifier)
    }

    private func setupLayout() {
        minimumThicknessForInlineSidebars = 180

        let itemA = NSSplitViewItem(sidebarWithViewController: vcA)
        itemA.minimumThickness = 80
        addSplitViewItem(itemA)

        let itemB = NSSplitViewItem(contentListWithViewController: vcB)
        itemB.minimumThickness = 100
        addSplitViewItem(itemB)

        let itemC = NSSplitViewItem(viewController: vcC)
        itemC.minimumThickness = 80
        addSplitViewItem(itemC)
    }
}

创建ViewController显示参照容器

import Cocoa

class ViewController: NSViewController {
    private let backgroundColor: NSColor

    init(backgroundColor: NSColor) {
        self.backgroundColor = backgroundColor
        super.init(nibName: nil, bundle: nil)
    }

    @available(*, unavailable)
    required init?(coder _: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func loadView() {
        view = NSView()
        view.wantsLayer = true
        view.layer?.backgroundColor = backgroundColor.cgColor
    }
}

保存项目,运行参考效果如下

自此就完成了一款无storyboard的macos app项目基础结构的搭建

参考资料

  1. https://medium.com/@theboi/creating-macos-apps-without-a-storyboard-or-xib-file-516115ee9d26
  2. https://nshipster.com/swift-format/
  3. https://stackoverflow.com/questions/44309088/nssplitviewcontroller-programmatically/46756790