Preferencesみたいなツールバータブウィンドウを作る

よくあるアプリのPreferencesウィンドウみたいなのを作ります。
ツールバーがタブの役割をしていて、タブを選択すると画面が切り替わります
![スクリーンショット 2016-07-14 17.42.03.png](https://qiita-image-store.s3.amazonaws.com/0/61792/a2352968-c1ef-9f1d-1768-cfd3e28251c2.png)

# 作り方
既存のツールバーをいじってもなかなかうまくいかなかったのですが、NSTabViewControllerなるものを使えば簡単にできます。

## TabViewControllerをStoryboardに追加
<img width="259" alt="スクリーンショット 2016-07-14 17.50.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/61792/e2a21a21-729f-cb4a-fded-7ca1b8ec63bd.png">

TabViewControllerをStoryboardに追加します。
そして、WindowControllerと関連づいているViewControllerを削除し、WindowControllerのwindow contentに追加したTabViewControllerを割り当てます。

TabViewControllerの設定ですが、StyleをToolbarに変更します。
<img width="261" alt="スクリーンショット 2016-07-14 18.01.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/61792/d70d215e-04f7-8471-f440-01282200183d.png">

## TabViewControllerのChildViewControllerをいじる
適当にいじります。今回は適当なラベルを追加しました。
今んとこViewControllerの構成は以下のようになっています。

<img width="1044" alt="スクリーンショット_2016-07-14_17_56_23.png" src="https://qiita-image-store.s3.amazonaws.com/0/61792/aff3e540-0b25-9d1b-c5da-49dbbe9d248c.png">

## ToolbarItemをいじる
上記まででタブでの画面切り替え自体は出来ますが、タブのアイコンがない状態ですのでシステムのアイコンをつけてみます。
（システムのアイコンについての詳細は、[System-Provided Images](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/SystemProvided.html#//apple_ref/doc/uid/20000957-CH92-SW3)を参照してみてください。）

1. NSTabViewControllerのサブクラスを作成。
2. InterfaceBulder上でNSTabViewControlleを手順1で作ったクラスに変更
2. InterfaceBulder上でTabViewControllerの下にNSTabViewItemがありますのでこれを手順1のサブクラスのOutletに追加。

<img width="349" alt="スクリーンショット 2016-07-14 18.09.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/61792/ddc913e8-044a-47c0-0808-482caf4b94b1.png">
4. NSTabViewControllerのサブクラスのコード内で、手順3で作ったオブジェクトのアイコンを設定。

```swift:TabViewController.swift
class TabViewController: NSTabViewController {

    @IBOutlet weak var generalItem: NSTabViewItem!
    @IBOutlet weak var accountItem: NSTabViewItem!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // アイコン設定
        accountItem.image = NSImage(named: NSImageNameUserAccounts)
        generalItem.image = NSImage(named: NSImageNamePreferencesGeneral)
    }
}
```
iOSのTabBarControllerみたいな感じでできました。

## (追記)タブ選択時に、Windowサイズを変更する
それぞれのタブのViewのサイズが異なる場合、タブ選択時にサイズを変更してあげる必要があります。

一番簡単なのは、AutoLayoutで各Viewのサイズを固定してしまうことです。
しかしこのやり方では、アニメーションがつかなかったので、以下のように実装しました。

### やり方
1. （必要なら）windowのリサイズを無効にする
<img width="262" alt="スクリーンショット_2016-07-14_19_46_06.png" src="https://qiita-image-store.s3.amazonaws.com/0/61792/8816ba05-6a90-f18c-bb53-c81ae73152b9.png">

2. TabViewをTabViewControllerのDelegateに設定する。
3. TabViewControllerにデリゲートメソッド ```tabView(tabView: NSTabView, willSelectTabViewItem tabViewItem: NSTabViewItem?)``` を追加し実装する。

上記のデリゲートメソッドはタブを選択した時に呼ばれます。この時にWindowサイズを変更するコードを実装します。

#### ソースコード
```swift:TabViewController.swift
class TabViewController: NSTabViewController {

    @IBOutlet weak var generalItem: NSTabViewItem!
    @IBOutlet weak var accountItem: NSTabViewItem!
    
    enum TabViewIdentifier: String {
        case GeneralIdentifier = "General"
        case AccountIdentifier = "Account"
        
        var tabViewType: TabViewType {
            switch self {
            case GeneralIdentifier:
                return TabViewType.General
            case AccountIdentifier:
                return TabViewType.Account
            }
        }
    }
    
    enum TabViewType: Int {
        case General
        case Account
        
        var windowSize: CGSize {
            switch self {
            case .General:
                return CGSizeMake(450, 160) //適当
            case .Account:
                return CGSizeMake(450, 280) //適当
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        accountItem.image = NSImage(named: NSImageNameUserAccounts)
        generalItem.image = NSImage(named: NSImageNamePreferencesGeneral)
    }
    
    // タブを選択した時に呼ばれる
    override func tabView(tabView: NSTabView, willSelectTabViewItem tabViewItem: NSTabViewItem?) {
        guard let window = self.view.window else { return }
        guard let identifier = tabViewItem?.identifier as? String else { return }
        guard let tabViewIdentifier = TabViewIdentifier(rawValue: identifier) else { return }
        
        let type = tabViewIdentifier.tabViewType
        let contentSize = type.windowSize
        let newWindowSize = window.frameRectForContentRect(CGRectMake(0, 0, contentSize.width, contentSize.height)).size
        
        var frame = window.frame
        frame.origin.y += frame.size.height
        frame.origin.y -= newWindowSize.height
        frame.size = newWindowSize
        
        // サイズ変更
        self.view.window?.setFrame(frame, display: false, animate: true)
    }
}
```