LoginSignup
9

More than 5 years have passed since last update.

OS X アプリでStoryboardとSegueを利用する ビューを切り替える編

Last updated at Posted at 2016-04-03

OS X アプリでStoryboardとSegueを利用する(概略)
に続いて実践編です

やること

標準で用意されているセグエをやってもつまらないのでカスタムセグエを利用した今すぐ使えるビューの遷移です。
ウインドウ内の一部をボタンクリックなどでスライドして別のビューに切り替えるセグエを作ります。

「OS Xアプリで」というわけで、iOSでは普通やらなくて、OS XではよくやるであろうWindow内の一部コンテンツの遷移を選びました。

ストーリーボードを作る

前回同様、WindowControllerを配置します。
ウインドウコンテントビューにすでにViewControllerというNSViewControllerが設定されていますのでそのまま利用します。

ウインドウコンテントビューにContainerViewを配置します。
一部が切り替わっていることが分かりやすいように右半分だけに配置しました。
スクリーンショット 2016-04-03 20.09.44.png

新しいNSViewControllerのクラスはそのままでOKです。
ボタンとラベルを配置しました。
スクリーンショット 2016-04-03 20.10.54.png

さらにもう一つViewControllerを配置します。カスタムクラスは設定不要です。
こちらもボタンとラベルを配置しました。
スクリーンショット 2016-04-03 20.11.02.png

このふたつのビューをセグエを利用して切り替えます。
ボタンの「Triggerd Segues」の「action」をもう一方のビューコントローラに接続します。接続先は「custom」を選択します。
全画面_2016_04_03_18_29 3.png

全画面_2016_04_03_18_29_2.png

設定したセグエのAttribute inspectorでClassを「SlideSegue」とします。このクラスは後で作ります。

全画面_2016_04_03_18_30 2.png

スクリーンショット 2016-04-03 18.30.46.png

同じ作業を行って双方向に同じセグエを設定します。

カスタムViewController

特に何も必要ないのですが、遷移アニメーション中にボタンを何度も押せてしまうのでそれを抑止します。

ViewController.m
#import "ViewController.h"

@implementation ViewController
- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(nullable id)sender
{
    // アニメーション開始後に動作させない
    if([sender respondsToSelector:@selector(setAction:)]) {
        [sender setAction:nil];
    }

    NSViewController *d = segue.destinationController;
    d.representedObject = self.representedObject;
}
@end

この
objc
- (void)prepareForSegue:sender:

は NSStoryboardSegue.h で宣言されている NSSeguePerforming プロトコルのメソッドです。
NSViewController, NSWindowControllerは標準でこのプロトコルに準拠しています。

- (void)prepareForSegue:sender: 

は名前の通り、セグエが発動する前に変化が起る親のオブジェクトに変化が起るビューコントローラに対してデータのセットなどを行うためのメソッドです。

ボタンを無効化してもいいのですが、見た目が変だったのでactionをなくすという強引な方法で2度目以降のクリックを無視するようにしました。

後ろの2行は今回は特に意味はありません。通常はこのようにrepresentedObjectを通じでデータのセットを行います。

カスタムSegue

カスタムSegueでビューコントローラの関係性の設定と遷移アニメーションの実行を行います。

SlideSegue.h
#import <Cocoa/Cocoa.h>

@interface SlideSegue : NSStoryboardSegue

@end
SlideSegue.m
#import "SlideSegue.h"

@implementation SlideSegue
- (void)perform
{
    // NSViewControllerの親子関係を設定
    NSViewController *s = self.sourceController;
    NSViewController *d = self.destinationController;
    NSViewController *p = s.parentViewController;
    if(![p.childViewControllers containsObject:d]) {
        [p addChildViewController:d];
    }

    // 遷移アニメーション
    [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) {
        context.duration = 0.5;

        NSRect frame = s.view.frame;
        frame.origin.x = frame.size.width;
        d.view.frame = frame;
        [s.view.superview addSubview:d.view];

        NSRect newDFrame = s.view.frame;

        NSRect newSFrame = s.view.frame;
        newSFrame.origin.x = -newSFrame.size.width;

        s.view.animator.frame = newSFrame;
        d.view.animator.frame = newDFrame;

        d.view.autoresizingMask = s.view.autoresizingMask;
    } completionHandler:^{
        // 今まで表示されていたNSViewControllerの親子関係を解除
        [s removeFromParentViewController];
        [s.view removeFromSuperview];
    }];
}
@end

基本的にNSStoryboardSegueのサブクラスではこのメソッドのみをオーバーライドして、セグエの動作を設定します。
セグエでは、アニメーションの定義だけではなく、ビューコントローラの関係性の設定も行います。

試してみよう

なんとこれで終わりです。

 ボタンを押すたびに、First ViewとSecond Viewが左にスライドして切り替わります。
カスタムSegueを変えるだけでアニメーションの変更が可能です。

自分で設定するのが面倒な方はGithubにレポジトリを作りましたのでそちらを見てください。
https://github.com/masakih/StoryboardSample01

まとめ

OS XでのStoryboard、Segueの資料が少なくてかなり困ってます。

変化するNSViewControllerの親子関係を誰がどのように設定するのか悩んでいたのですが、最終的にNSStoryboardSegueのリファレンスで

A storyboard segue specifies a transition or containment relationship between two scenes in a storyboard,

という記述を見つけてセグエがそれを担えばいいというのに気付きました。

リファレンスはちゃんと読みましょう。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9