Xamarin.iOS のストーリーボード

このガイドでは、ストーリーボードとは何かを説明し、セグエなどの主要なコンポーネントをいくつか調べます。 ストーリーボードを作成して使用する方法と、開発者にとってどのような利点があるかを見ていきます。

Apple が iOS アプリケーションの UI の視覚的表現としてストーリーボード ファイル形式を導入する前に、開発者たちがビュー コントローラーごとに XIB ファイルを作成し、各ビュー間のナビゲーションを手動でプログラミングしました。 ストーリーボードを使用すると、開発者はビュー コントローラーとそれらの間のナビゲーションの両方をデザイン サーフェイス上で定義し、アプリケーションのユーザー インターフェイスの WYSIWYG 編集を提供きます。

ストーリーボードは、Visual Studio for Mac で作成して開くことができます。 このガイドでは、Xcode Interface Builder を使用してストーリーボードを作成し、C# を使用してナビゲーションをプログラミングする方法についても説明します。

要件

ストーリーボードは Xcode で使用でき、Visual Studio for Mac の Xamarin.iOS プロジェクト内から起動できます。

ストーリーボードとは?

ストーリーボードは、アプリケーション内のすべての画面の視覚的表現です。 一連のシーンが含まれており、各シーンはビュー コントローラーとそのビューを表します。 これらのビューには、ユーザーがアプリケーションを操作できるようにするオブジェクトとコントロールが含まれている場合があります。 このビューとコントロール (またはサブビュー) のコレクションは、"コンテンツ ビュー階層" と呼ばれます。 シーンはセグエ オブジェクトによって接続されます。これは、ビュー コントローラー間の遷移を表します。 これは通常、最初のビュー上のオブジェクトと接続ビューの間にセグエを作成することによって実現できます。 デザイン サーフェイス上のリレーションシップを次の図に示します。

この図にはデザイン サーフェイス上のリレーションシップが示されています

図に示すように、ストーリーボードは、コンテンツが既にレンダリングされている各シーンをレイアウトし、それらの間の接続を示します。 iPhone のシーンの場合、ストーリーボード上の 1 つのシーンがデバイス上のコンテンツの 1 つの画面と等しいと考えることができます。 ただし、iPad では、複数のシーンを一度に表示することができます。たとえば Popover ビュー コントローラーを使用した場合です。

アプリケーションの UI の作成にストーリーボードを使用することは、特に Xamarin を使用する場合に多くの利点があります。 まず、すべてのオブジェクト (カスタム コントロールを含む) がデザイン時にレンダリングされるため、UI の視覚的表現となります。 つまり、アプリケーションをビルドまたはデプロイする前に、その外観とフローを視覚化できます。 たとえば、前の画像をご覧ください。 デザイン サーフェイスを簡単に見るだけでも、シーンの数、各ビューのレイアウト、すべての関連性がわかります。 これがストーリーボードが強力な理由です。

ストーリーボードを使用してイベントを管理することもできます。 ほとんどの UI コントロールには、Properties Pad に可能性のあるイベントの一覧があります。 ここにイベント ハンドラーを追加して、ビュー コントローラーのクラスの部分メソッドで完了できます。

ストーリーボードの内容は XML ファイルとして保存されます。 ビルド時には、すべての .storyboard ファイルがニブと呼ばれるバイナリ ファイルにコンパイルされます。 実行時に、これらのニブは初期化され、新しいビューを作成するためにインスタンス化されます。

セグエ

セグエ (セグエ オブジェクトとも呼ばれます) は、シーン間の遷移を表すために iOS 開発で使用されます。 セグエを作成するには、Ctrl キーを押しながら、シーン間でクリックとドラッグを実行します。 マウスをドラッグすると、セグエがリードする場所を示す青いコネクタが表示されます。 これを次の画像に示します。

青いコネクタが表示され、この画像で示すようにセグエがリードする場所を示します

カーソルを上に置くと、セグエのアクションを選択できるメニューが表示されます。 次の画像のようになります。

iOS 8 より前のクラスとサイズ クラス:

サイズ クラスのない [Action Segue] ドロップダウン

サイズ クラスとアダプティブ セグエを使用する場合:

サイズ クラスを含む [Action Segue] ドロップダウン

重要

Windows 仮想マシンに VMWare を使用している場合、Ctrl キー + クリックは既定では右クリック マウス ボタンとしてマップされています。 セグエを作成するには、[基本設定]>[キーボードとマウス]>[マウス ショートカット] からキーボードの設定を編集し、次に示すようにセカンダリ ボタンを再マッピングします。

キーボードとマウスの基本設定

これで、ビュー コントローラー間で通常どおりセグエを追加できるようになりました。

さまざまな種類の画面切り替えがあり、それぞれが新しいビュー コントローラーをユーザーに表示する方法と、ストーリーボード内の他のビュー コントローラーと対話する方法を制御できます。 これらについて以下に詳しく説明します。 セグエ オブジェクトをサブクラス化してカスタム遷移を実装することもできます。

  • 表示/プッシュ – プッシュ セグエは、ビュー コントローラーをナビゲーション スタックに追加します。 プッシュ元のビュー コントローラーが、スタックに追加されるビュー コントローラーと同じナビゲーション コントローラーの一部であることを前提としています。 これは pushViewController と同じように機能し、画面のデータ間に何らかの関係がある場合に一般的に使用されます。 プッシュ セグエを使用すると、[戻る] ボタンとタイトルがスタック上の各ビューに追加されたナビゲーション バーが用意され、ビュー階層のナビゲーションをドリルダウンできます。

  • モーダル – モーダル セグエは、アニメーション化された画面切り替えを表示するオプションを使用して、プロジェクト内の任意の 2 つのビュー コントローラー間にリレーションシップを作成します。 子ビュー コントローラーは、ビューに取り込まれると、親ビュー コントローラーを完全に隠します。 [戻る] ボタンを追加するプッシュ セグエとは異なり、モーダル セグエを使用するときに前のビュー コントローラーに戻るには、DismissViewController を使用する必要があります。

  • カスタム – 任意のカスタム セグエを UIStoryboardSegue のサブクラスとして作成できます。

  • アンワインド – アンワインド セグエを使用すると、モーダル表示ビュー コントローラーを閉じるなどして、プッシュまたはモーダル セグエ内を戻ることができます。 これに加えて、1 つだけでなく一連のプッシュおよびモーダル セグエを使用してアンワインドし、1 つのアンワインド アクションを使用してナビゲーション階層内の複数のステップに戻ることができます。 iOS でアンワインド セグエを使用する方法については、「アンワインド セグエを作成する」のレシピをご覧ください。

  • ソースレス – ソースレス セグエは、初期ビュー コントローラーを含むシーンを示すことで、ユーザーが最初に表示するビューを示します。 これは、次に示すセグエによって表されます。

    ソースレス セグエ

アダプティブ セグエ型

iOS 8 ではサイズ クラスが導入され、iOS ストーリーボード ファイルが使用可能なすべての画面サイズで動作し、開発者はすべての iOS デバイスに対して 1 つの UI を作成できるようになりました。 既定では、すべての新しい Xamarin.iOS アプリケーションでサイズ クラスが使用されます。 古いプロジェクトのサイズ クラスを使用するには、「Xamarin.iOS の統合ストーリーボード」ガイドをご覧ください。

サイズ クラスを使用するアプリケーションでは、新しいアダプティブ セグエも使用されます。 覚えておくべき点として、サイズ クラスを使用する場合、iPhone または iPad のどちらを使用しているかを直接指定することはありません。 つまり、使用する必要があるエステートの量に関係なく、常に同じように見える 1 つの UI を作成します。 アダプティブ セグエは、環境を判断し、コンテンツを提示する最善の方法を決定することによって機能します。 アダプティブ セグエを次に示します。

[Adaptive Segues] ドロップダウン

セグエ 説明
表示 これはプッシュ セグエによく似ていますが、画面の内容を考慮します。
詳細の表示 アプリにマスター ビューと詳細ビューが表示される場合 (たとえば、iPad の Split View コントローラー内)、コンテンツによって詳細ビューが置き換えられます。 アプリにマスターまたは詳細のみが表示される場合は、ビュー コントローラー スタックの上部がコンテンツによって置き換えられます。
プレゼンテーション これはモーダル セグエに似ていて、プレゼンテーションスタイルと切り替えスタイルを選択できます。
Popover プレゼンテーション これにより、コンテンツが Popover として表示されます。

セグエを使用したデータの転送

セグエの利点は、遷移では終わりません。 ビュー コントローラー間のデータ転送を管理するためにも使用できます。 これは、初期ビュー コントローラーで PrepareForSegue メソッドをオーバーライドし、データを自分で処理することで実現できます。 セグエがトリガーされると (ボタンを押した場合など)、アプリケーションはこのメソッドを呼び出し、ナビゲーションが発生する前に新しいビュー コントローラーを準備する機会を提供します。 その例を次のコードに示します。

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

    var callHistoryController = segue.DestinationViewController
                                  as CallHistoryController;

    if (callHistoryController != null) {
        callHistoryController.PhoneNumbers = PhoneNumbers;
    }
}

この例では、ユーザーによってセグエがトリガーされたときに PrepareForSegue メソッドが呼び出されます。 まず、'receiving' ビュー コントローラーのインスタンスを作成し、これをセグエの宛先ビュー コントローラーとして設定する必要があります。 これは、次のコード行によって行われます。

var callHistoryController = segue.DestinationViewController as CallHistoryController;

これで、メソッドに DestinationViewController のプロパティを設定する機能が追加されました。 この例ではその機能を利用して、PhoneNumbers というリストを CallHistoryController に渡し、同じ名前のオブジェクトに割り当てます。

if (callHistoryController != null) {
        callHistoryController.PhoneNumbers = PhoneNumbers;
    }

切り替えが完了すると、ユーザーに CallHistoryController と入力された一覧が表示されます。

ストーリーボード以外のプロジェクトにストーリーボードを追加する

場合によっては、ストーリーボード以外のファイルにストーリーボードを追加することが必要になる場合があります。 次の手順に従って、Visual Studio for Mac のプロセスを効率化できます。

  1. [ファイル] > [新しいファイル] > [iOS] > [ストーリーボード] を参照して、新しいストーリーボード ファイルを作成します。

    新しいファイルのダイアログ

  2. ストーリーボード名を Info.plist[メイン インターフェイス] セクションに追加します。

    Info.plist エディター

    これは、アプリ デリゲート内の FinishedLaunching メソッドで初期ビュー コントローラーをインスタンス化することと同じです。 このオプションを設定すると、アプリケーションはウィンドウをインスタンス化し (次の手順を参照)、メイン ストーリーボードを読み込み、ストーリーボードの初期ビュー コントローラー (ソースレス セグエの横にあるもの) のインスタンスをウィンドウの RootViewController プロパティとして割り当てます。 その後、ウィンドウが画面に表示されます。

  3. AppDelegate で、既定の Window メソッドを次のコードでオーバーライドして、window プロパティを実装します。

    public override UIWindow Window {
        get;
        set;
    }
    

Xcode を使用してストーリーボードを作成する

ストーリーボードは、Visual Studio for Mac で開発された iOS アプリで使用するために、Xcode を使用して作成および変更できます。

ストーリーボードはプロジェクト内の個々の XIB ファイルを完全に置き換えますが、ストーリーボード内の個々のビュー コントローラーは Storyboard.InstantiateViewController を使用してインスタンス化できます。

アプリケーションには、Designer によって提供された組み込みのストーリーボード遷移では処理できない特別な要件がある場合があります。 たとえば、アプリケーションの現在の状態に応じて、同じボタンから異なる画面を起動するアプリケーションを作成する場合、ビュー コントローラーを手動でインスタンス化し、遷移を自分でプログラムすることができます。

次のスクリーンショットは、デザイン サーフェイス上の 2 つのビュー コントローラーの間にセグエがない状態を示しています。 次のセクションでは、コードでその遷移を設定する方法について説明します。

  1. 既存のプロジェクトに空の iPhone ストーリーボードを追加します。

    ストーリーボードの追加

  2. ストーリーボード ファイルをダブルクリックするか、右クリックして [アプリケーションから開く] > [Xcode Interface Builder] の順に選んで Xcode Interface Builder で開きます。

  3. Xcode でライブラリを開き ([ビュー] > [ライブラリの表示] または Shift + Command + L)、ストーリーボードに追加できるオブジェクトの一覧を表示します。 リストからストーリーボードにオブジェクトをドラッグして、ストーリーボードに Navigation Controller を追加します。 既定では、Navigation Controller は 2 つの画面を提供します。 右側の画面は TableViewController です。これを削除できるように、より単純なビューに置き換えます。ビューをクリックして Delete キーを押します。

    ライブラリからの NavigationController の追加

  4. このビュー コントローラーには独自のカスタム クラスがあり、独自のストーリーボード ID も必要です。 この新しく追加されたビューの上にあるボックスをクリックすると、3 つのアイコンが表示され、そのうち左端のものはビューのビュー コントローラーを表します。 このアイコンを選択すると、右側のウィンドウの ID タブでクラスと ID の値を設定できます。これらの値を MainViewController に設定し、 Use Storyboard ID のチェックボックスを必ずオンにします。

    ID パネルでの MainViewController の設定

  5. ライブラリをもう一度使用して、ビュー コントローラー コントロールを画面にドラッグします。 これはルート ビュー コントローラーとして設定されます。 Ctrl キーを押しながら、左側のナビゲーション コントローラーから右側の新しく追加されたビュー コントローラーをクリックしてドラッグし、メニューで [ルート ビュー コントローラー] を選びます。

    ライブラリから NavigationController を追加し、MainViewController をルート ビュー コントローラーとして設定する

  6. このアプリは別のビューに移動するため、前と同じようにストーリーボードにもう 1 つのビューを追加します。 PinkViewController と呼び、MainViewController と同じ方法でこの値を設定します。

    3 つのビューを含むストーリーボードを示すスクリーンショット。

  7. ビュー コントローラの背景はピンク色になるので、そのプロパティを設定します。これを行うには、属性パネルで Background の隣のドロップダウンを使用します。

    スクリーンショットは、右端の画面がピンクの背景に変更された前の手順のストーリーボードを示しています。

  8. MainViewControllerPinkViewController に移動できるようにする必要があるため、前者には操作するボタンが必要です。 ライブラリを使用して MainViewController にボタンを追加します。

    MainViewController へのボタンの追加

ストーリーボードは完了しましたが、プロジェクトをデプロイすると、空の画面が表示されます。 これは、ストーリーボードを使用するように IDE に指示し、最初のビューとして機能するようにルート ビュー コントローラーを設定する必要があるためです。 前述のように、これは通常、プロジェクト オプションを使用して行うことができます。 ただし、この例では、同じ結果を得るために次のコードを AppDelegate に追加します。

public partial class AppDelegate : UIApplicationDelegate
{
    UIWindow window;
    public static UIStoryboard Storyboard = UIStoryboard.FromName ("MainStoryboard", null);
    public static UIViewController initialViewController;

    public override bool FinishedLaunching (UIApplication app, NSDictionary options)
    {
        window = new UIWindow (UIScreen.MainScreen.Bounds);

        initialViewController = Storyboard.InstantiateInitialViewController () as UIViewController;

        window.RootViewController = initialViewController;
        window.AddSubview(initialViewController.View);
        window.MakeKeyAndVisible ();
        return true;
    }
}

コードが多いですが、未知の行は数行だけです。 最初に、ストーリーボードの名前 MainStoryboard を渡すことで、ストーリーボードを AppDelegate に登録します。 次に、ストーリーボードの InstantiateInitialViewController を呼び出してストーリーボードから初期ビュー コントローラーをインスタンス化するようにアプリケーションに指示し、そのビュー コントローラーをアプリケーションのルート ビュー コントローラーとして設定します。 このメソッドは、ユーザーに表示される最初の画面を決定し、そのビュー コントローラーの新しいインスタンスを作成します。

手順 4 で Properties Pad にクラス名を追加したときに、IDE によってソリューション ウィンドウに MainViewcontroller.cs クラスとそれに対応する *.designer.cs ファイルが作成されたことにご注目ください。 このクラスにより、基底クラスを含む特別なコンストラクターが作成されました。

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

Xcode を使用してストーリーボードを作成すると、IDE は自動的に [Register] 属性を *.designer.cs クラスの先頭に追加し、文字列識別子を渡します。これは、前の手順で指定したストーリーボード ID と同じものです。 これにより、C# がストーリーボード内の関連するシーンにリンクされます。

[Register ("MainViewController")]
public partial class MainViewController : UIViewController
{
    public MainViewController (IntPtr handle) : base (handle)
    {
    }
    //...
}

クラスとメソッドの登録の詳細については、「型 Registrar」をご覧ください。

このクラスの最後の手順は、ボタンとピンクのビュー コントローラーへの切り替えを接続することです。 ストーリーボードから PinkViewController をインスタンス化します。その後、次のコードの例に示すように、プッシュ セグエで PushViewControllerプログラムします。

public partial class MainViewController : UIViewController
{
    UIViewController pinkViewController;

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

    public override void AwakeFromNib ()
    {
        // Called when loaded from xib or storyboard.
        this.Initialize ();
    }

    public void Initialize()
    {
        //Instantiating View Controller with Storyboard ID 'PinkViewController'
        pinkViewController = Storyboard.InstantiateViewController ("PinkViewController") as PinkViewController;
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();

        //When we push the button, we will push the pinkViewController onto our current Navigation Stack
        PinkButton.TouchUpInside += (o, e) =>
        {
            this.NavigationController.PushViewController (pinkViewController, true);
        };
    }
}

アプリケーションを実行すると、2 画面のアプリケーションが生成されます。

サンプル アプリの実行画面

条件付きセグエ

多くの場合、ビュー コントローラー間の移動は、特定の条件に依存しています。 たとえば、単純なログイン画面を作成していた場合は、ユーザー名とパスワードが検証された場合にのみ、次の画面に移動する必要があります。

次の例では、前のサンプルにパスワード フィールドを追加します。 ユーザーは、正しいパスワードを入力した場合にのみ PinkViewController にアクセスでき、それ以外の場合はエラーが表示されます。

開始する前に、前の手順 1 - 8 に従います。 これらの手順では、ストーリーボードを作成し、UI の作成を開始し、RootViewController として使用するビュー コントローラーをアプリ デリゲートに指示します。

  1. 次に、UI を構築し、次のスクリーンショットのように表示されるように、MainViewController に追加で記載されているビューを追加します。

    • UITextField
      • 名前: PasswordTextField
      • プレースホルダー: '秘密のパスワードを入力してください'
    • UILabel
      • テキスト: 'エラー: パスワードが間違っています。 通過できません。'
      • [Color]: 赤色
      • 配置: 中央
      • 行: 2
      • [非表示] チェックボックスをオンにする

    中心線

  2. [ピンクへ移動] ボタンとビュー コントローラーの間にセグエを作成します。これを行うには、PinkButton から PinkViewController に Ctrl キーを押しながらドラッグし、マウスを離すときに [プッシュ] を選びます。

  3. セグエをクリックして識別子 を指定します。SegueToPink

    セグエをクリックして識別子 SegueToPink を指定します

  4. 最後に、MainViewController クラスに次の ShouldPerformSegue メソッドを追加します。

    public override bool ShouldPerformSegue (string segueIdentifier, NSObject sender)
    {
    
        if(segueIdentifier == "SegueToPink"){
            if (PasswordTextField.Text == "password") {
                PasswordTextField.ResignFirstResponder ();
                return true;
            }
            else{
                ErrorLabel.Hidden = false;
                return false;
            }
        }
        return base.ShouldPerformSegue (segueIdentifier, sender);
    }
    

このコードでは、segueIdentifier を SegueToPink セグエと一致させたので、条件 (この場合は有効なパスワード) をテストできます。 条件が true を返した場合、セグエは実行して PinkViewController を提示します。 false の場合、新しいビュー コントローラーは表示されません。

この方法は、このビュー コントローラー上の任意のセグエに適用できます。これを行うには、segueIdentifier 引数を ShouldPerformSegue メソッドにチェックします。 この場合、セグエ識別子は 1 つだけです (SegueToPink)。

まとめ

この記事では、ストーリーボードの概念と、それらが iOS アプリケーションの開発にどのように役立つのかについて説明します。 シーン、ビュー コントローラー、ビュー、ビュー階層について取り上げ、シーンがさまざまな種類のセグエとどのようにリンクするかについて説明します。 また、ストーリーボードからビュー コントローラーを手動でインスタンス化し、条件付きセグエを作成する方法についても説明します。