C#
Storyboard
Xamarin
segue
Xamarin.Mac

Xamarin.Mac開発でStoryboardを初めて触る人に贈る、Xamarin公式 Working with Storyboards の日本語訳記事

More than 1 year has passed since last update.

Xamarin.Macを初めて触る人に贈る、Xamarin公式 Hello, Mac の日本語訳記事に引き続き。

Xamarin.Mac を開発するときに使う Storyboard やその中で扱う View Controller、 Segue、 Window Controller に馴染みがなかったので公式記事で勉強するついでに日本語訳しました。

この記事の内容と一番下で紹介されている SourceWriter Sample App を追えば多少キャッチアップできるかなぁと思っています。

Storyboard

Storyboard は、特定のアプリのすべての UI を View Controller の機能概要に分けて定義します。 Xcode の Interface Builder では、これらのコントローラーはそれぞれ独自の Scene に存在します。
スクリーンショット 2017-08-17 23.00.45.png

Storyboard は、Xamarin.Mac アプリケーションのバンドルがコンパイルされて送り出されるときに含まれるリソースファイル(拡張子は .storyboard )です。アプリケーションの最初の Storyboard を定義するには Info.plist ファイルを編集し、ドロップダウンボックスから Main Interface を選択します。

スクリーンショット 2017-08-17 23.08.51.png

コードからのロード

コードから特定の Storyboard をロードし、View Controller を手動で作成する必要がある場合があります。次のコードでそれが可能です。

// Get new window
var storyboard = NSStoryboard.FromName ("Main", null);
var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

// Display
controller.ShowWindow(this);

FromName は、アプリケーションのバンドルに含まれている特定の名前の Storyboard ファイルを読み込みます。InstantiateControllerWithIdentifier は、指定された ID を持つ View Controller のインスタンスを生成します。UI をデザインするときに、Xcode の Interface Builder で ID を設定します。

スクリーンショット 2017-08-17 23.18.07.png

必要に応じて、InstantiateInitialController メソッドを使用して、Interface Builder で最初の Controller が割り当てられた View Controller をロードすることができます。

スクリーンショット 2017-08-17 23.20.35.png

Storyboard Entry Point と矢印でマークされています。

View Controller

View Controller は、Mac アプリケーション内の特定の View の情報とその情報を提供するデータモデルとの関係を定義します。Storyboard の各トップレベル scene は、Xamarin.Mac アプリのコード内の1つの View Controller を表します。

View Controller のライフサイクル

macOS で Storyboard をサポートするために NSViewController クラスにいくつかの新しいメソッドが追加されました。最も重要なのは、特定の View Controllerによって制御されている View のライフサイクルに応答するために使用される以下のメソッドです。

  • ViewDidLoad - このメソッドは、ビューが Storyboard ファイルからロードされたときに呼び出されます。
  • ViewWillAppear - このメソッドは、ビューが画面に表示される直前に呼び出されます。
  • ViewDidAppear - このメソッドは、ビューが画面に表示された直後に呼び出されます。
  • ViewWillDisappear - このメソッドは、ビューが画面から削除される直前に呼び出されます。
  • ViewDidDisappear - このメソッドは、ビューが画面から削除された直後に呼び出されます。
  • UpdateViewConstraints - このメソッドは、ビューの自動レイアウトの位置とサイズを定義する制約が更新される必要があるときに呼び出されます。
  • ViewWillLayout - このメソッドは、このビューのサブビューが画面上に配置される直前に呼び出されます。
  • ViewDidLayout - このメソッドは、ビューのサブビューが画面上に配置された直後に呼び出されます。

Responder Chain

さらに、NSViewController は ウィンドウの Responder Chain の一部になりました。

スクリーンショット 2017-08-17 23.41.39.png

また、カット、コピー、ペーストのメニュー項目の選択などのイベントを受けて​​応答するために繋がれています。この自動の View Controller 配線は、Mac OS X Yosemite (10.10)以上で動作するアプリでのみ発生します。

Containment

Storyboard では、View Controller ( Split View Controller や Tab View Controller など)は、他のサブビューコントローラを「含む」ように、 Containment を実装できます。

スクリーンショット 2017-08-17 23.48.15.png

子 View Controller には、それらを親 View Controller に結びつけ、画面から View を表示または削除するためのメソッドとプロパティが含まれています。

macOSに組み込まれているすべての Container View Controller には、独自のカスタム Container View Controller を作成する場合に Apple が推奨する特定のレイアウトがあります。

スクリーンショット 2017-08-17 23.54.33.png

Collection View Controller には、それぞれ独自の View を含む1つまたは複数の View Controller が含まれる Collection View Item の配列が含まれています。

Segue

Segue は、アプリの UI を定義するすべての Scene 間の関係を提供します。iOS の Storyboard での作業に馴染みがある場合は、通常、iOS 向けの Segue ではフルスクリーンビュー間の遷移を定義していることをご存知でしょう。これは macOS と異なります。Segue は通常「 Containment 」を定義し、ある Scene は親 Scene の子です。

macOSでは、ほとんどのアプリは Split View や Tab などの UI 要素を使用して同じウィンドウ内でビューをグループ化する傾向があります。物理的な表示スペースが限られているために画面の表示と非表示を切り替える必要があるiOSとは異なります。

Presentation Segue

macOSの containment には Modal Window, Sheet View、Popover などのPresentation Segue の使用が多いです。macOS は次の組み込み segue タイプを提供します。

  • Show - Segue のターゲットを非モーダルウィンドウとして表示します。たとえば、このタイプのSegueを使用して、アプリケーションに Document Window の別のインスタンスを表示します。
  • Modal - Segue のターゲットをモーダルウィンドウとして表示します。たとえば、このタイプのSegueを使用して、アプリケーションのPreferences Window を表示します。
  • Sheet - 親ウィンドウにアタッチされた Sheet として Segue のターゲットを表示します。たとえば、このタイプの Segue を使用して Find and Replace Sheet を表示します。
  • Popover - ポップオーバーウィンドウのように Segue のターゲットを表示します。たとえば、この Segue タイプを使用して、ユーザーが UI 要素をクリックしたときのオプションを表示します。
  • ** Custom** - 開発者が定義したカスタム Segue タイプを使用して Segue のターゲットを表示します。詳細については、以下のカスタム Segue 作成セクションを参照してください。

Presentation Segue を使用する場合は、親 View Controller の PrepareForSegue メソッドを表示の初期化のためにオーバーライドし、 View Controller に任意のデータを提供できます。(訳注: ここ訳怪しい… variable が何の目的語かわかりません)

Triggered Segue

Triggered Segue では、( Interface Builder の Identifier プロパティーを介して)名前付き Segue を指定し、ユーザーがボタンをクリックするか、コード内の PerformSegue メソッドを呼び出すなどのイベントによってトリガーさせることができます。

// Display the Scene defined by the given Segue ID
PerformSegue("MyNamedSegue", this);

Segue ID は、アプリケーションの UI をレイアウトするときに、 Xcode の Interface Builder 内で定義されます。

スクリーンショット 2017-08-18 19.43.19.png

Segue のソースとして動作している View Controller では、Segueが実行されて指定された View Controller が表示される前に、PrepareForSegue メソッドをオーバーライドして初期化を行う必要があります。

public override void PrepareForSegue (NSStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    // Take action based on Segue ID
    switch (segue.Identifier) {
    case "MyNamedSegue":
        // Prepare for the segue to happen
        ...
        break;
    }
}

必要に応じて、ShouldPerfromSegue メソッドをオーバーライドして、Segue が C# コードで実際に実行されるかどうかを制御できます。手動で表示された View Controller の場合は、DismissController メソッドを呼び出して必要なくなったときに表示から削除します。

カスタム Segue の作成

アプリケーションを作成するにあたり、macOS の組み込み Segue では提供されていない Segue タイプが必要なときもあります。そういうときは、アプリの UI をレイアウトするときに Xcode の Interface Builder で 割り当てることができるカスタム Segue を作成することができます。

たとえば、(新しいウィンドウでターゲット Scene を開く代わりに)ウィンドウ内の現在の View Controller を置き換える新しい Segue タイプを作成するには、次のコードを使用します。

using System;
using AppKit;
using Foundation;

namespace OnCardMac
{
    [Register("ReplaceViewSeque")]
    public class ReplaceViewSeque : NSStoryboardSegue
    {
        #region Constructors
        public ReplaceViewSeque() {

        }

        public ReplaceViewSeque (string identifier, NSObject sourceController, NSObject destinationController) : base(identifier,sourceController,destinationController) {

        }

        public ReplaceViewSeque (IntPtr handle) : base(handle) {
        }

        public ReplaceViewSeque (NSObjectFlag x) : base(x) {
        }
        #endregion

        #region Override Methods
        public override void Perform ()
        {
            // Cast the source and destination controllers
            var source = SourceController as NSViewController;
            var destination = DestinationController as NSViewController;

            // Swap the controllers
            source.View.Window.ContentViewController = destination;

            // Release memory
            source.RemoveFromParentViewController ();
        }
        #endregion

    }

}

いくつか注意すべきことがあります。

  • このクラスを Objective-C / macOS に公開するために、 Register 属性を使用しています。
  • カスタム Segue のアクションを実行するために Perform メソッドをオーバーライドしています。
  • Window の ContentViewController コントローラを、 Segue のターゲット(行き先)によって定義されたものに置き換えます。
  • 元の View Controller を削除し、 RemoveFromParentViewController メソッドを使用してメモリを解放します。

この新しい Segue タイプを Xcode の Interface Builder で使用するには、まずアプリケーションをコンパイルしてから Xcode に切り替え、2つの Scene の間に新しい Segue を追加する必要があります。 StyleCustom に設定し、 Segue ClassReplaceViewSegue (カスタム Segue クラスの名前)に設定します。

スクリーンショット 2017-08-18 20.08.49.png

Window Controller

Window Controller は macOS アプリケーションが作成できるさまざまな Window タイプを含み、制御します。Storyboard の場合、以下の機能があります。

  1. Content View Controller を提供する必要があります。これは、子 Window と同じ Content View Controller になります。
  2. Storyboard プロパティには、 Window Controller のロード元の Storyboard が含まれます。Storyboard からロードされていない場合は、 null が返されます。
  3. DismissController メソッドを呼び出して、指定された Window を閉じてビューから削除することができます。

View Controller と同様に、Window Controller は PerformSeguePrepareForSegueShouldPerfromSegue メソッドを実装し、Segue 操作のソースとして使用できます。

Window Controller は macOS アプリケーションの以下の機能を担います。

  • 特定の Window を管理します。
  • Window の Title Bar と Toolbar (使用可能な場合)を管理します。
  • Content View Controller を管理して、Window の内容を表示します。

Gesture Recognizer

macOS の Gesture Recognizer は、iOS の機能とほぼ同じです。開発者は、アプリの UI の要素にジェスチャー(マウスボタンをクリックするなど)を簡単に追加することができます。

しかし、iOS のジェスチャーがアプリのデザイン(2本の指で画面をタップするなど)によって決まるとすると、macOS のほとんどのジェスチャーはハードウェアによって決まります。Gesture Recognizer を使用すると、UI のアイテムにカスタムインタラクションを追加するのに必要なコード量を大幅に削減できます。ダブルクリックとシングルクリックを自動的に判断できます。

View Controller で MouseDown イベントをオーバーライドする代わりに、Storyboard を操作する際に Gesture Recognizer を使用してユーザー入力イベントを処理すべきです。

macOS では、以下の Gesture Recognizer が利用できます。

  • NSClickGestureRecognizer - マウスダウン・アップのイベントを登録します。
  • NSPanGestureRecognizer - マススボタンダウン、ドラッグ、離すイベントを登録します。
  • NSPressGestureRecognizer - 特定時間マウスボタンを押し続けるイベントを登録します。
  • NSMagnificationGestureRecognizer - トラックパッドから倍率イベントを登録します。
  • NSRotationGestureRecognizer - トラックパッドからの回転イベントを登録します。

Storyboard Reference の使用

Storyboard Reference を使用すると、大きく複雑な Storyboard デザインを取り込んで、元の Storyboard から参照される小さな Storyboard に分割し、複雑さを排除します。その結果、個々の Storyboard の設計と保守を容易にすることができます。

さらに、Storyboard Reference は、同じ Storyboard 内の別の Scene または別の Storyboard の特定の Scene に アンカー を提供することができます。

外部 Storyboard の参照

外部 Storyboard への参照を追加するには、次の手順を実行します。

  1. ソリューションエクスプローラ でプロジェクト名を右クリックし、 Add > New Fole... > Mac > Storyboard うぃ選択します。新しい Storyboard の Name を入力し、New ボタンをクリックします。

スクリーンショット 2017-08-18 20.58.47.png

  1. ソリューションエクスプローラで、新しい Storyboard 名をダブルクリックし、Xcode のInterface Builderで編集するために開きます。

  2. いつものように新しい Storyboard の scene のレイアウトをデザインし、変更を保存します。

スクリーンショット 2017-08-18 21.00.43.png

  1. Interface Builderで参照を追加する Storyboard に切り替えます。
  2. Storyboard ReferenceObject Library からデザインサーフェスにドラッグします。

スクリーンショット 2017-08-18 21.04.33.png

  1. Attribute Inspector で、上記で作成した Storyboard の名前を選択します。

スクリーンショット 2017-08-18 21.05.46.png

  1. 既存の Scene のUI ウィジェット(ボタンのような)を Control + クリックし、作成した Storyboard Reference の新しい Segue を作成します。Segue を完了するためにポップアップメニューから Show を選択します。

スクリーンショット 2017-08-18 21.11.02.png

  1. Storyboard への変更を保存します。
  2. Xamarin Studioに戻り、変更を同期します。

アプリが実行され、ユーザーが Segue を作成した UI 要素をクリックすると、Storyboard Referenceで指定された外部 Storyboard の Initial Window Controller が表示されます。

外部 Storyboard 内特定の Scene の参照

外部 Storyboard (で Initial Window Controller でないもの)の特定の Scene への参照を追加するには、以下を実行します。

  1. ソリューションエクスプローラ で、外部 Storyboard をダブルクリックして、Xcode の Interface Builder で編集するために開きます。
  2. 新しい Scene を追加し、普段どおりにそのレイアウトをデザインします。

スクリーンショット 2017-08-18 21.18.11.png

  1. Identity Inspector で新しい Scene の Window Controller の Storyboard ID を入力します。

スクリーンショット 2017-08-18 21.19.59.png

  1. Interface Builder で参照を追加する Storyboard を開きます。
  2. Storyboard ReferenceObject Library からデザインサーフェスにドラッグします。

スクリーンショット 2017-08-18 21.22.03.png

  1. Identity Inspector で、Storyboard の名前と上記で作成したシーンのReference ID( Storyboard ID )を選択します。

スクリーンショット 2017-08-18 21.24.26.png

  1. 既存の Scene のUI ウィジェット(ボタンのような)を Control + クリックし、作成した Storyboard Reference の新しい Segue を作成します。Segue を完了するためにポップアップメニューから Show を選択します。

スクリーンショット 2017-08-18 21.26.23.png

  1. Storyboard への変更を保存します。
  2. Xamarin Studioに戻り、変更を同期します。

アプリが実行され、ユーザーが Segue を作成した UI 要素をクリックすると、Storyboard Referenceで指定された外部 Storyboard から特定の Storyboard ID を持つ Scene が表示されます。

同じ Storyboard の特定 Scene の参照

同じ Storyboard の特定の Scene への参照を追加するには、以下を実行します。

  1. ソリューションエクスプローラ で、 Storyboard をダブルクリックして編集するために開きます。
  2. 新しい Scene を追加し、普段どおりにそのレイアウトをデザインします。

スクリーンショット 2017-08-18 21.31.13.png

  1. Identity Inspector で、新しい Scene の Window Controller の Storyboard ID を入力します。

スクリーンショット 2017-08-18 21.32.43.png

  1. Storyboard Reference を ** Toolbox** からデザインサーフェスにドラッグします。

スクリーンショット 2017-08-18 21.33.56.png

  1. Attribute Inspector で、上記で作成した Scene の Reference ID (Storyboard ID)を選択します。

スクリーンショット 2017-08-18 21.36.02.png

  1. 既存の Scene のUI ウィジェット(ボタンのような)を Control + クリックし、作成した Storyboard Reference の新しい Segue を作成します。Segue を完了するためにポップアップメニューから Show を選択します。

スクリーンショット 2017-08-18 21.37.04.png

  1. Storyboard への変更を保存します。
  2. Xamarin Studioに戻り、変更を同期します。

アプリケーションが実行され、ユーザーが Segue を作成した UI 要素をクリックすると、Storyboard Reference で指定された同じ Storyboard 内の指定された Storyboard ID を持つ Scene
が表示されます。

複雑な Storyboard の例

Xamarin.Mac アプリケーションで Storyboards を操作する複雑な例については、SourceWriter Sample App を参照してください。SourceWriter は、コード補完と簡単な構文ハイライトをサポートするシンプルなソースコードエディタです。

SourceWriter コードはコメント付きで、利用可能な場合は重要なテクノロジーや方法から Xamarin.Mac
ガイドの関連情報へのリンクが提供されています。