Xamarin.iOS のスタック ビュー
この記事では、Xamarin.iOS アプリで新しい UIStackView コントロールを使用して、水平方向または垂直方向に配置されたスタックで一連のサブビューを管理する方法について説明します。
重要
iOS Designer では StackView がサポートされていますが、安定チャネルの使用時に使いやすさのバグが発生する可能性があることに注意してください。 ベータまたはアルファ チャネルを切り替えると、この問題が軽減されます。 必要な修正プログラムが安定チャネルに実装されるまで、Xcode を使用してこのチュートリアルを紹介することにしました。
スタック ビュー コントロール (UIStackView
) は、自動レイアウトとサイズ調整クラスの機能を利用して、iOS デバイスの向きと画面サイズに動的に対応するサブビューのスタック (水平方向または垂直方向) を管理します。
スタック ビューにアタッチされているすべてのサブビューのレイアウトは、軸、分布、配置、間隔などの開発者が定義したプロパティに基づいてスタック ビューによって管理されます。
Xamarin.iOS アプリで UIStackView
を使用する場合、開発者は、iOS Designer のストーリーボード内で、または C# コードでサブビューを追加および削除することで、サブビューを定義できます。
このドキュメントは、最初のスタック ビューの実装に役立つクイック スタートと、その動作に関する技術的な詳細の 2 つの部分で構成されています。
UIStackView ビデオ
UIStackView クイック スタート
UIStackView
コントロールの簡単な紹介として、ユーザーが 1 から 5 で評価を入力できるシンプルなインターフェイスを作成する予定です。 2 つのスタック ビューを使用します。1 つはデバイスの画面上でインターフェイスを垂直方向に配置し、もう 1 つは 1 から 5 の評価アイコンを画面全体に水平方向に配置します。
UI を定義する
新しい Xamarin.iOS プロジェクトを開始し、Xcode の Interface Builder で Main.storyboard ファイルを編集します。 最初に、View Controller で 1 つの垂直スタック ビューをドラッグします。
[Attribute Inspector]で、次のオプションを設定します。
ここで:
- Axis – スタック ビューによってサブビューが水平方向または垂直方向に配置されるかどうかを決定します。
- 配置 – スタック ビュー内でのサブビューの配置方法を制御します。
- 分布 – スタック ビュー内でサブビューのサイズを設定する方法を制御します。
- Spacing – スタック ビュー内での各サブビュー間の最小スペースを制御します。
- Baseline Relative – オンにした場合、各サブビューの垂直方向のスペースは、そのベースラインから派生します。
- Layout Margins Relative – 標準レイアウトの余白を基準にサブビューを配置します。
スタック ビューを使用する場合、[Alignment] はサブビューの X と Y の位置、[Distribution] は高さと幅として考えることができます。
重要
UIStackView
は、非レンダリング コンテナー ビューとして設計されているため、UIView
のその他のサブクラスとは異なり、キャンバスに描画されません。 そのため、BackgroundColor
などのプロパティを設定したり、DrawRect
をオーバーライドしたりしても、視覚的な効果はありません。
次のようになるように、ラベル、イメージビュー、2 つのボタン、水平スタック ビューを追加して、アプリのインターフェイスのレイアウトを続けます。
次のオプションを使用して、水平スタック ビューを構成します。
評価の各 "ポイント" を表すアイコンが水平スタック ビューに追加されたときに伸縮されないようにするために、[Alignment] を [Center] に、[Distribution] を [Fill Equally] に設定しました。
最後に、次の Outlets と Actions を接続します。
コードから UIStackView を設定する
Visual Studio for Mac に戻り、ViewController.cs ファイルを編集して次のコードを追加します。
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 Mode を Scale Aspect Fit に設定します。
var icon = new UIImageView (new UIImage("icon.png"));
icon.ContentMode = UIViewContentMode.ScaleAspectFit;
これにより、"星" アイコンがスタック ビューに追加されたときに歪むことを防止できます。
次に、新しい "星" アイコンをスタック ビューのサブビューのコレクションに追加します。
RatingView.AddArrangedSubview(icon);
UIImageView
を UIStackView
の SubView
ではなく ArrangedSubviews
プロパティに追加したことに注意してください。 スタック ビューでレイアウトを制御するビューは、ArrangedSubviews
プロパティに追加する必要があります。
スタック ビューからサブビューを削除するには、まず、削除するサブビューを取得します。
var icon = RatingView.ArrangedSubviews[RatingView.ArrangedSubviews.Length-1];
次に、それを ArrangedSubviews
コレクションとスーパー ビューの両方から削除する必要があります。
// Remove from stack and screen
RatingView.RemoveArrangedSubview(icon);
icon.RemoveFromSuperview();
ArrangedSubviews
コレクションだけからサブビューを削除した場合、スタック ビューのコントロールからは外れますが、画面からは削除されません。
UI のテスト
必要なすべての UI 要素とコードを配置したので、インターフェイスを実行してテストできるようになりました。 UI が表示されると、垂直スタック ビュー内のすべての要素が上から下に等間隔に配置されます。
ユーザーが [Increase Rating] ボタンをタップすると、新たな "星" が画面に追加されます (最大 5 つまで)。
"星" は自動的に中央に配置され、水平スタック ビューで均等に分散されます。 ユーザーが [Decrease Rating] ボタンをタップすると、"星" が 1 つずつ (すべて消えるまで) 削除されます。
スタック ビューの詳細
これで、UIStackView
コントロールの概要と動作について確認したので、その機能と詳細についてさらに詳しく見ていきましょう。
自動レイアウトおよびサイズ クラス
前述のように、サブビューをスタック ビューに追加すると、配置されたビューを配置およびサイズ変更するために、そのレイアウトが自動レイアウト クラスとサイズ クラスを使用してスタック ビューによって完全に制御されます。
スタック ビューでは、コレクション内の最初と最後のサブビューが、垂直スタック ビューの場合は上端と下端、水平スタック ビューの場合は左端と右端に "ピン留め" されます。 LayoutMarginsRelativeArrangement
プロパティを true
に設定すると、サブビューは端ではなく、関連する余白にピン留めされます。
スタック ビューでは、定義された Axis
に沿ったサブビューのサイズを計算するときにサブビューの IntrinsicContentSize
プロパティが使用されます (FillEqually Distribution
は除きます)。 FillEqually Distribution
の場合、すべてのサブビューのサイズが同じになるようにサイズが変更され、これにより、Axis
に沿ってスタック ビューが塗りつぶされます。
Fill Alignment
を除き、スタック ビューでは、指定された Axis
ビューに対して垂直なビューのサイズを計算するためにサブビューの IntrinsicContentSize
プロパティが使用されます。 Fill Alignment
の場合、すべてのサブビューによって指定されたAxis
に対して垂直なスタック ビューが塗りつぶされるように、これらのサブビューのサイズが設定されます。
スタック ビューの配置とサイズ設定
サブビューのレイアウトは (Axis
や Distribution
などのプロパティに基づいて) スタック ビューによって完全に制御されますが、ユーザーは依然として、自動レイアウト クラスとサイズ クラスを使用して親ビュー内にスタック ビュー (UIStackView
) を配置する必要があります。
一般に、これは、スタック ビューの少なくとも 2 つの端をピン留めして拡大および縮小し、その位置を定義することを意味します。 追加の制約がない場合、スタック ビューは次のように、すべてのサブビューをサイズに合わせて調整するために自動的にサイズ変更されます。
Axis
に沿ったサイズは、すべてのサブビューのサイズの合計に、各サブビュー間で定義されたスペースを足した値になります。LayoutMarginsRelativeArrangement
プロパティがtrue
である場合、スタック ビューのサイズには余白のスペースも含まれます。Axis
に対して垂直なサイズは、コレクション内の最大サブビューに設定されます。
また、スタック ビューの高さと幅の制約を指定することもできます。 この場合、サブビューは、Distribution
および Alignment
プロパティによって決定されたとおりにスタック ビューによって指定されたスペースを塗りつぶすようにレイアウト (サイズ設定) されます。
BaselineRelativeArrangement
プロパティが true
である場合、サブビューは、上、下、または中心- Y の位置ではなく、最初または最後のサブビューのベースラインに基づいてレイアウトされます。 これらは、次のようにスタック ビューのコンテンツで計算されます。
- 垂直スタック ビューにより、最初のベースラインに対して最初のサブビュー、および最後のベースラインに対して最後のサブビューが返されます。 これらのいずれかのサブビュー自体がスタック ビューである場合は、最初または最後のベースラインが使用されます。
- 水平スタック ビューにより、最初のベースラインと最後のベースラインの両方に対して最も高いサブビューが使用されます。 最も高いビューがスタック ビューでもある場合は、最も高いサブビューがベースラインとして使用されます。
重要
ベースラインの配置は、拡大または圧縮されたサブビューのサイズに対しては機能しません。なぜなら、ベースラインの計算結果が間違った位置になるからです。 ベースライン配置の場合、サブビューの高さが組み込みコンテンツ ビューの高さと一致していることを確認します。
一般的なスタック ビューの用途
スタック ビュー コントロールで適切に動作するレイアウトの種類がいくつかあります。 Apple によると、いくつかの一般的な用途には次のものがあります。
- 軸に沿ったサイズの定義 – スタック ビューの
Axis
に沿って両方の端をピン留めし、隣接する端の 1 つを固定して位置を設定することで、サブビューで定義されたスペースに合うようにスタック ビューが軸に沿って拡大されます。 - サブビューの位置の定義 – スタック ビューの隣接する端を親ビューにピン留めすることで、スタック ビューは、含まれるサブビューに合うように両方向に拡大されます。
- スタック ビューのサイズと位置の定義 – スタック ビューの4つの端をすべて親ビューにピン留めすることで、スタック ビューによってスタック ビュー内で定義されたスペースに基づいてサブビューが配置されます。
- 軸に垂直なサイズの定義 – スタック ビューの
Axis
に垂直な両方の端と、軸に沿った端の 1 つエッジをピン留めして位置を設定することで、スタック ビューはサブビューで定義されたスペースに合わせて軸に垂直に拡大されます。
外観の管理
UIStackView
は、非レンダリング コンテナー ビューとして設計されているため、UIView
のその他のサブクラスとは異なり、キャンバスに描画されません。 BackgroundColor
などのプロパティを設定しても、DrawRect
をオーバーライドしても、視覚的な効果はありません。
スタック ビューでサブビューのコレクションを配置する方法を制御するプロパティがいくつかあります。
- 軸 – スタック ビューによってサブビューが水平方向または垂直方向に配置されるかどうかを決定します。
- 配置 – スタック ビュー内でのサブビューの配置方法を制御します。
- 分布 – スタック ビュー内でサブビューのサイズを設定する方法を制御します。
- 間隔 – スタック ビュー内の各サブビュー間の最小スペースを制御します。
- ベースライン基準 –
true
である場合、各サブビューの垂直方向の間隔は、そのベースラインから派生します。 - レイアウト余白基準 – 標準レイアウトの余白を基準にサブビューを配置します。
通常、スタック ビューを使用して、少数のサブビューを配置します。 1 つ以上のスタック ビューを相互に入れ子にすることで、より複雑なユーザー インターフェイスを作成できます (上記の UIStackView クイック スタートで行ったように)。
サブビューに制約を追加することで、UI の外観をさらに微調整できます (たとえば、高さや幅を制御できます)。 ただし、スタック ビュー自体によって導入されたサブビューに競合する制約を含めないように注意する必要があります。
配置ビューとサブビューの整合性の維持
スタック ビューでは、次の規則を使用して、Subviews
プロパティが常に ArrangedSubviews
プロパティのサブセットであるようにします。
ArrangedSubviews
コレクションに追加されたサブビューは、自動的にSubviews
コレクションに追加されます (そのコレクションに既に含まれている場合を除く)。Subviews
コレクションから削除 (表示から削除) されたサブビューは、ArrangedSubviews
コレクションからも削除されます。- サブビューを
ArrangedSubviews
コレクションから削除しても、Subviews
コレクションからは削除されません。 そのため、スタック ビューによってレイアウトされなくなりますが、画面には引き続き表示されます。
ArrangedSubviews
コレクションは常に Subview
コレクションのサブセットですが、各コレクション内の個々のサブビューの順序は、以下によって個別に制御されます。
ArrangedSubviews
コレクション内のサブビューの順序によって、スタック内での表示順序が決まります。Subview
コレクション内のサブビューの順序によって、ビュー内の Z オーダー (またはレイヤー化) が決まります (後ろから前)。
コンテンツを動的に変更する
スタック ビューでは、サブビューが追加、削除、または非表示になるたびに、サブビューのレイアウトが自動的に調整されます。 スタック ビューのいずれかのプロパティ (Axis
など) を調整すると、レイアウトも調整されます。
レイアウトの変更は、アニメーション ブロック内に配置することでアニメーション化できます。次に例を示します。
// Animate stack
UIView.Animate(0.25, ()=>{
// Adjust stack view
RatingView.LayoutIfNeeded();
});
スタック ビューのプロパティの多くは、ストーリーボード内のサイズ クラスを使用して指定できます。 これらのプロパティは、サイズや向きの変更に応じて自動的にアニメーション化されます。
まとめ
この記事では、Xamarin.iOS アプリで水平方向または垂直方向に配置されたスタックで一連のサブビューを管理するための新しい UIStackView
コントロール (iOS 9 用) について説明しました。
スタック ビューを使用して UI を作成する簡単な例から始まり、スタック ビューとそのプロパティおよび機能について詳しく説明しました。