Xamarin での tvOS スタック ビューの操作

警告

iOS Designer は、Visual Studio 2019 バージョン 16.8 および Visual Studio 2019 for Mac バージョン 8.8 で非推奨とされ、Visual Studio 2019 バージョン 16.9 および Visual Studio for Mac バージョン 8.9 から削除されています。 iOS のユーザー インターフェイスについては、Xcode の Interface Builder が実行されている Mac で直接ビルドすることをお勧めします。 詳細については、「Xcode を使用したユーザーインターフェイスの設計」を参照してください。

スタック ビュー コントロール (UIStackView) は、自動レイアウト クラスとサイズ クラスの機能を利用して、Apple TV デバイスのコンテンツ変更と画面サイズに動的に対応するサブビューのスタック (水平方向または垂直方向) を管理します。

スタック ビューにアタッチされているすべてのサブビューのレイアウトは、軸、分布、配置、間隔などの開発者が定義したプロパティに基づいてスタック ビューによって管理されます。

サブビュー レイアウト図

Xamarin.tvOS アプリで UIStackView を使用する場合、開発者は、iOS Designer のストーリーボード内で、または C# コードでサブビューを追加および削除することで、サブビューを定義できます。

スタック ビュー コントロールについて

UIStackView は、非レンダリング コンテナー ビューとして設計されているため、UIView のその他のサブクラスのようにはキャンバスに描画されません。 BackgroundColor などのプロパティを設定しても、DrawRect をオーバーライドしても、視覚的な効果はありません。

スタック ビューでサブビューのコレクションを配置する方法を制御するプロパティがいくつかあります。

  • – スタック ビューによってサブビューが水平方向または垂直方向に配置されるかどうかを決定します。
  • 配置 – スタック ビュー内でのサブビューの配置方法を制御します。
  • 分布 – スタック ビュー内でサブビューのサイズを設定する方法を制御します。
  • 間隔 – スタック ビュー内の各サブビュー間の最小スペースを制御します。
  • ベースライン基準true である場合、各サブビューの垂直方向の間隔は、そのベースラインから派生します。
  • レイアウト余白基準 – 標準レイアウトの余白を基準にサブビューを配置します。

通常、スタック ビューを使用して、少数のサブビューを配置します。 1 つ以上のスタック ビューを相互に入れ子にすることで、より複雑なユーザー インターフェイスを作成できます。

サブビューに制約を追加することで、UI の外観をさらに微調整できます (たとえば、高さや幅を制御できます)。 ただし、スタック ビュー自体によって導入されたサブビューに競合する制約を含めないように注意する必要があります。

自動レイアウト クラスとサイズ クラス

サブビューをスタック ビューに追加すると、配置されたビューを配置およびサイズ変更するために、そのレイアウトが自動レイアウト クラスとサイズ クラスを使用してスタック ビューによって完全に制御されます。

スタック ビューでは、コレクション内の最初と最後のサブビューが、垂直スタック ビューの場合は端と端、水平スタック ビューの場合は端と端にピン留めされます。 LayoutMarginsRelativeArrangement プロパティを true に設定すると、サブビューは端ではなく、関連する余白にピン留めされます。

スタック ビューでは、定義された Axis に沿ったサブビューのサイズを計算するときにサブビューの IntrinsicContentSize プロパティが使用されます (FillEqually Distribution は除きます)。 FillEqually Distribution の場合、すべてのサブビューのサイズが同じになるようにサイズが変更され、これにより、Axis に沿ってスタック ビューが塗りつぶされます。

Fill Alignment を除き、スタック ビューでは、指定された Axis ビューに対して垂直なビューのサイズを計算するためにサブビューの IntrinsicContentSize プロパティが使用されます。 Fill Alignment の場合、すべてのサブビューによって指定されたAxis に対して垂直なスタック ビューが塗りつぶされるように、これらのサブビューのサイズが設定されます。

スタック ビューの配置とサイズ設定

サブビューのレイアウトは (AxisDistribution などのプロパティに基づいて) スタック ビューによって完全に制御されますが、ユーザーは依然として、自動レイアウト クラスとサイズ クラスを使用して親ビュー内にスタック ビュー (UIStackView) を配置する必要があります。

一般に、これは、スタック ビューの少なくとも 2 つの端をピン留めして拡大および縮小し、その位置を定義することを意味します。 追加の制約がない場合、スタック ビューは次のように、すべてのサブビューをサイズに合わせて調整するために自動的にサイズ変更されます。

  • Axis に沿ったサイズは、すべてのサブビューのサイズの合計に、各サブビュー間で定義されたスペースを足した値になります。
  • LayoutMarginsRelativeArrangement プロパティが true である場合、スタック ビューのサイズには余白のスペースも含まれます。
  • Axis に対して垂直なサイズは、コレクション内の最大サブビューに設定されます。

また、スタック ビューの高さの制約を指定することもできます。 この場合、サブビューは、Distribution および Alignment プロパティによって決定されたとおりにスタック ビューによって指定されたスペースを塗りつぶすようにレイアウト (サイズ設定) されます。

BaselineRelativeArrangement プロパティが true である場合、サブビューは、、または中心 - Y の位置ではなく、最初または最後のサブビューのベースラインに基づいてレイアウトされます。 これらは、次のようにスタック ビューのコンテンツで計算されます。

  • 垂直スタック ビューにより、最初のベースラインに対して最初のサブビュー、および最後のベースラインに対して最後のサブビューが返されます。 これらのいずれかのサブビュー自体がスタック ビューである場合は、最初または最後のベースラインが使用されます。
  • 水平スタック ビューにより、最初のベースラインと最後のベースラインの両方に対して最も高いサブビューが使用されます。 最も高いビューがスタック ビューでもある場合は、最も高いサブビューがベースラインとして使用されます。

重要

ベースラインの配置は、拡大または圧縮されたサブビューのサイズに対しては機能しません。なぜなら、ベースラインの計算結果が間違った位置になるからです。 ベースライン配置の場合、サブビューの高さが組み込みコンテンツ ビューの高さと一致していることを確認します。

一般的なスタック ビューの用途

スタック ビュー コントロールで適切に動作するレイアウトの種類がいくつかあります。 Apple によると、いくつかの一般的な用途には次のものがあります。

  • 軸に沿ったサイズの定義 – スタック ビューの Axis に沿って両方の端をピン留めし、隣接する端の 1 つを固定して位置を設定することで、サブビューで定義されたスペースに合うようにスタック ビューが軸に沿って拡大されます。
  • サブビューの位置の定義 – スタック ビューの隣接する端を親ビューにピン留めすることで、スタック ビューは、含まれるサブビューに合うように両方向に拡大されます。
  • スタック ビューのサイズと位置の定義 – スタック ビューの4つの端をすべて親ビューにピン留めすることで、スタック ビューによってスタック ビュー内で定義されたスペースに基づいてサブビューが配置されます。
  • 軸に垂直なサイズの定義 – スタック ビューの Axis に垂直な両方の端と、軸に沿った端の 1 つエッジをピン留めして位置を設定することで、スタック ビューはサブビューで定義されたスペースに合わせて軸に垂直に拡大されます。

スタック ビューとストーリーボード

Xamarin.tvOS アプリでスタック ビューを操作する最も簡単な方法は、iOS Designer を使用してアプリの UI に追加することです。

  1. Solution PadMain.storyboard ファイルをダブルクリックして、編集用に開きます。

  2. スタック ビューに追加する個々の要素のレイアウトを設計します。

    要素レイアウトの例

  3. 要素が正しくスケーリングされるように、要素に必要な制約を追加します。 この手順は、要素がスタック ビューに追加された後に重要になります。

  4. 必要な数のコピーを作成します (この場合は 4 つ)。

    必要な部数

  5. ツールボックスからスタック ビューをドラッグし、ビューにドロップします。

    スタック ビュー

  6. スタック ビューを選択し、Properties Pad[ウィジェット] タブで、[配置][塗りつぶし] を選択し、[分布][均等に塗りつぶし] を選択し、[間隔] に「25」と入力します。

    [ウィジェット] タブ

  7. スタック ビューを画面の目的の場所に配置し、必要な場所に保持するために制約を追加します。

  8. 個々の要素を選択し、スタック ビューにドラッグします。

    スタック ビューの個々の要素

  9. レイアウトが調整され、上記で設定した属性に基づいてスタック ビューに要素が配置されます。

  10. C# コードで UI コントロールを操作するために、Properties Explorer[ウィジェット] タブに [名前] を割り当てます。

  11. 変更を保存します。

重要

イベント ハンドラーの作成時に iOS Designer で TouchUpInside などのアクションを UI 要素 (UIButton など) に割り当てることは可能ですが、Apple TV にはタッチ スクリーンがないか、タッチ イベントをサポートしていないため、このアクションが呼び出されることはありません。 tvOS ユーザー インターフェイス要素のアクションを作成する場合は、常に既定の Action Type を使用する必要があります。

ストーリーボードの使用の詳細については、「はじめての tvOS クイック スタート ガイド」を参照してください。

この例では、セグメント コントロールに対してアウトレットとアクションを、"プレイヤー カード" ごとにアウトレットを公開しました。 コードでは、現在のセグメントに基づいてプレーヤーの非表示と表示を切り替えます。 次に例を示します。

partial void PlayerCountChanged (Foundation.NSObject sender) {

    // Take Action based on the segment
    switch(PlayerCount.SelectedSegment) {
    case 0:
        Player1.Hidden = false;
        Player2.Hidden = true;
        Player3.Hidden = true;
        Player4.Hidden = true;
        break;
    case 1:
        Player1.Hidden = false;
        Player2.Hidden = false;
        Player3.Hidden = true;
        Player4.Hidden = true;
        break;
    case 2:
        Player1.Hidden = false;
        Player2.Hidden = false;
        Player3.Hidden = false;
        Player4.Hidden = true;
        break;
    case 3:
        Player1.Hidden = false;
        Player2.Hidden = false;
        Player3.Hidden = false;
        Player4.Hidden = false;
        break;
    }
}

アプリを実行すると、スタック ビューで4 つの要素が均等に分散されます。

アプリを実行すると、スタック ビューで4 つの要素が均等に分散されます

プレイヤーの数が減ると、未使用のビューは非表示になり、スタック ビューによってレイアウトがサイズに合わせて調整されます。

プレイヤーの数が減ると、未使用のビューは非表示になり、スタック ビューによってレイアウトがサイズに合わせて調整されます

コードからのスタック ビューの設定

iOS Designer でスタック ビューのコンテンツとレイアウトを完全に定義するだけでなく、C# コードから動的に作成および削除することもできます。

次の例では、スタック ビューを使用してレビューの "星" (stars) を処理します (1 から 5)。

public int Rating { get; set;} = 0;
...

partial void IncreaseRating (Foundation.NSObject sender) {

    // Maximum of 5 "stars"
    if (++Rating > 5 ) {
        // Abort
        Rating = 5;
        return;
    }

    // Create new rating icon and add it to stack
    var icon = new UIImageView (new UIImage("icon.png"));
    icon.ContentMode = UIViewContentMode.ScaleAspectFit;
    RatingView.AddArrangedSubview(icon);

    // Animate stack
    UIView.Animate(0.25, ()=>{
        // Adjust stack view
        RatingView.LayoutIfNeeded();
    });

}

partial void DecreaseRating (Foundation.NSObject sender) {

    // Minimum of zero "stars"
    if (--Rating < 0) {
        // Abort
        Rating =0;
        return;
    }

    // Get the last subview added
    var icon = RatingView.ArrangedSubviews[RatingView.ArrangedSubviews.Length-1];

    // Remove from stack and screen
    RatingView.RemoveArrangedSubview(icon);
    icon.RemoveFromSuperview();

    // Animate stack
    UIView.Animate(0.25, ()=>{
        // Adjust stack view
        RatingView.LayoutIfNeeded();
    });
}

このコードのいくつかの部分を詳しく見てみましょう。 まず、if ステートメントを使用して、"星" の数が 5 より大きくないか、または 0 より小さくないかを確認します。

新しい "星" を追加するには、そのイメージを読み込み、Content ModeScale Aspect Fit に設定します。

var icon = new UIImageView (new UIImage("icon.png"));
icon.ContentMode = UIViewContentMode.ScaleAspectFit;

これにより、"星" アイコンがスタック ビューに追加されたときに歪むことを防止できます。

次に、新しい "星" アイコンをスタック ビューのサブビューのコレクションに追加します。

RatingView.AddArrangedSubview(icon);

UIImageViewUIStackViewSubView ではなく ArrangedSubviews プロパティに追加したことに注意してください。 スタック ビューでレイアウトを制御するビューは、ArrangedSubviews プロパティに追加する必要があります。

スタック ビューからサブビューを削除するには、まず、削除するサブビューを取得します。

var icon = RatingView.ArrangedSubviews[RatingView.ArrangedSubviews.Length-1];

次に、それを ArrangedSubviews コレクションとスーパー ビューの両方から削除する必要があります。

// Remove from stack and screen
RatingView.RemoveArrangedSubview(icon);
icon.RemoveFromSuperview();

ArrangedSubviews コレクションだけからサブビューを削除した場合、スタック ビューのコントロールからは外れますが、画面からは削除されません。

コンテンツの動的変更

スタック ビューでは、サブビューが追加、削除、または非表示になるたびに、サブビューのレイアウトが自動的に調整されます。 スタック ビューのいずれかのプロパティ (Axis など) を調整すると、レイアウトも調整されます。

レイアウトの変更は、アニメーション ブロック内に配置することでアニメーション化できます。次に例を示します。

// Animate stack
UIView.Animate(0.25, ()=>{
    // Adjust stack view
    RatingView.LayoutIfNeeded();
});

スタック ビューのプロパティの多くは、ストーリーボード内のサイズ クラスを使用して指定できます。 これらのプロパティは、サイズや向きの変更に応じて自動的にアニメーション化されます。

まとめ

この記事では、Xamarin.tvOS アプリ内でのスタック ビューの設計と使用について説明しました。