Xamarin.Forms Visual State Manager
コードから設定されたビジュアル状態に基づいて XAML 要素を変更するには、Visual State Manager を使用します。
Visual State Manager (VSM) は、コードからユーザー インターフェイスに視覚的な変更を加える構造化された方法を提供します。 ほとんどの場合、アプリケーションのユーザー インターフェイスは XAML で定義されており、この XAML には、Visual State Manager がユーザー インターフェイスのビジュアルに与える影響を説明するマークアップが含まれています。
VSM では、 ビジュアル状態の概念が導入されています。 Xamarin.FormsなどのButton
ビューには、基になる状態に応じて、無効か押されているか、入力フォーカスがあるかに応じて、いくつかの異なる外観を持つことができます。 これらはボタンの状態です。
ビジュアル状態は、 ビジュアル状態グループで収集されます。 ビジュアル状態グループ内のすべてのビジュアル状態は、相互に排他的です。 ビジュアル状態とビジュアル状態グループの両方が、単純なテキスト文字列によって識別されます。
Visual State Manager では Xamarin.Forms 、"CommonStates" という名前の 1 つのビジュアル状態グループが定義され、次のビジュアル状態が定義されます。
- "Normal"
- "無効"
- "Focused"
- "選択済み"
このビジュアル状態グループは、 および Page
の基底クラスである からVisualElement
派生するすべてのクラスでView
サポートされています。
この記事で示すように、独自のビジュアル状態グループとビジュアル状態を定義することもできます。
注意
Xamarin.Formsトリガーに精通している開発者は、トリガーは、ビューのプロパティの変更やイベントの発生に基づいて、ユーザー インターフェイスのビジュアルに変更を加えることもできます。 ただし、トリガーを使用してこれらの変更のさまざまな組み合わせを処理すると、非常に混乱する可能性があります。 これまで、Visual State Manager は、視覚的な状態の組み合わせによる混乱を軽減するために、Windows XAML ベースの環境で導入されていました。 VSM では、ビジュアル状態グループ内のビジュアル状態は常に相互に排他的です。 常に、各グループ内の 1 つの状態のみが現在の状態になります。
一般的な状態
Visual State Manager を使用すると、ビューが正常であるか無効になっているか、入力フォーカスがある場合にビューの外観を変更できるマークアップを XAML ファイルに含めることができます。 これらは 一般的な状態と呼ばれます。
たとえば、ページにビューがあり Entry
、 の視覚的な外観を次の Entry
方法で変更するとします。
- が
Entry
無効になっている場合、 にはピンク色のEntry
背景が必要です。 - は
Entry
通常、ライムの背景を持つ必要があります。 - は
Entry
、入力フォーカスがある場合、通常の高さの 2 倍に拡大する必要があります。
VSM マークアップを個々のビューにアタッチすることも、複数のビューに適用される場合はスタイルで定義することもできます。 次の 2 つのセクションでは、これらの方法について説明します。
ビューの VSM マークアップ
VSM マークアップをビューに Entry
アタッチするには、最初に を Entry
開始タグと終了タグに分けます。
<Entry FontSize="18">
</Entry>
状態の 1 つが プロパティを使用 FontSize
して 内のテキストのサイズを 2 倍にするため、明示的なフォント サイズが Entry
与えられます。
次に、これらのタグの間にタグを挿入 VisualStateManager.VisualStateGroups
します。
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualStateGroups
は、 クラスによって VisualStateManager
定義されたバインド可能な添付プロパティです。 (添付されたバインド可能なプロパティの詳細については、 添付プロパティに関する記事を参照してください)。これは、 プロパティを VisualStateGroups
オブジェクトにアタッチする Entry
方法です。
プロパティの型VisualStateGroupList
はVisualStateGroups
、 オブジェクトのVisualStateGroup
コレクションです。 タグ内に VisualStateManager.VisualStateGroups
、含めるビジュアル状態のグループごとにタグの VisualStateGroup
ペアを挿入します。
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
タグには VisualStateGroup
、グループの名前を x:Name
示す属性があることに注意してください。 クラスは VisualStateGroup
、 Name
代わりに使用できるプロパティを定義します。
<VisualStateGroup Name="CommonStates">
または をx:Name
Name
使用できますが、両方を同じ要素で使用することはできません。
クラスは VisualStateGroup
、 オブジェクトのコレクションである という名前 States
の VisualState
プロパティを定義します。 States
は の content プロパティVisualStateGroups
であるため、タグ間VisualStateGroup
にタグをVisualState
直接含めることができます。 (コンテンツ プロパティについては、「 基本的な XAML 構文」を参照してください)。
次の手順では、そのグループ内のすべてのビジュアル状態に対してタグのペアを含めます。 これらは、 または Name
を使用してx:Name
識別することもできます。
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
</VisualState>
<VisualState x:Name="Focused">
</VisualState>
<VisualState x:Name="Disabled">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
VisualState
は、 オブジェクトのコレクションである という名前 Setters
の Setter
プロパティを定義します。 これらは、オブジェクトで使用するのとStyle
同じSetter
オブジェクトです。
Setters
は の content プロパティ ではありません 。そのため、 プロパティ VisualState
のプロパティ要素タグを Setters
含める必要があります。
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
タグの各ペアの間に 1 つ以上 Setter
のオブジェクトを Setters
挿入できるようになりました。 前に説明した Setter
ビジュアル状態を定義するオブジェクトを次に示します。
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
各 Setter
タグは、その状態が現在の場合に特定のプロパティの値を示します。 オブジェクトによって参照されるすべてのプロパティは、 Setter
バインド可能なプロパティによってサポートされている必要があります。
このようなマークアップは、VsmDemos サンプル プログラムの [表示] ページの VSM の基礎です。 ページには 3 つの Entry
ビューが含まれていますが、VSM マークアップがアタッチされているのは 2 番目のビューのみです。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:VsmDemos"
x:Class="VsmDemos.MainPage"
Title="VSM Demos">
<StackLayout>
<StackLayout.Resources>
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>
<Label Text="Normal Entry:" />
<Entry />
<Label Text="Entry with VSM: " />
<Entry>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>
<Label Text="Entry to enable 2nd Entry:" />
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
2 番目 Entry
の には、 DataTrigger
コレクションの一部として も含まれることに注意してください Trigger
。 これにより、3 番目Entry
の Entry
に何かが入力されるまで、 が無効になります。 iOS、Android、ユニバーサル Windows プラットフォーム (UWP) で実行されている起動時のページを次に示します。
現在のビジュアル状態は "無効" であるため、iOS および Android 画面では 2 番目 Entry
の画面の背景がピンク色になります。 の UWP 実装 Entry
では、 が無効になっている場合に背景色を Entry
設定できません。
3 番目 Entry
の にテキストを入力すると、2 番目 Entry
のテキストが "標準" 状態に切り替わります。背景はライムになりました。
2 つ目 Entry
の をタッチすると、入力フォーカスが取得されます。 "Focused" 状態に切り替え、その高さの 2 倍に拡張されます。
Entry
では、入力フォーカスを取得してもライムの背景は保持されないことに注意してください。 Visual State Manager がビジュアル状態を切り替えるにつれて、前の状態によって設定されたプロパティは設定解除されます。 ビジュアルの状態は相互に排他的であることに注意してください。 "Normal" 状態は、 が有効であるという Entry
意味ではありません。 これは、 が Entry
有効であり、入力フォーカスがないことを意味します。
に "Focused" 状態のライム背景を含める場合 Entry
は、そのビジュアル状態に別の Setter
背景を追加します。
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
これらの Setter
オブジェクトが正しく機能するためには、 には、 VisualStateGroup
そのグループ内のすべての状態のオブジェクトが含まれている VisualState
必要があります。 オブジェクトがない視覚的な状態 Setter
がある場合は、空のタグとして含めます。
<VisualState x:Name="Normal" />
スタイルの Visual State Manager マークアップ
多くの場合、2 つ以上のビュー間で同じ Visual State Manager マークアップを共有する必要があります。 この場合は、マークアップを定義に Style
配置します。
VSM On View ページの要素に対するEntry
既存の暗黙的Style
な情報を次に示します。
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
</Style>
添付されたバインド可能なプロパティのVisualStateManager.VisualStateGroups
タグを追加Setter
します。
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
</Setter>
</Style>
の content プロパティ Setter
は Value
であるため、これらのタグ内で Value
プロパティの値を直接指定できます。 そのプロパティの型 VisualStateGroupList
は です。
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
</VisualStateGroupList>
</Setter>
</Style>
これらのタグ内には、次 VisualStateGroup
のいずれかのオブジェクトを含めることができます。
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
VSM マークアップの残りの部分は、以前と同じです。
完全な VSM マークアップを示す VSM in Style ページを次に示します。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmInStylePage"
Title="VSM in Style">
<StackLayout>
<StackLayout.Resources>
<Style TargetType="Entry">
<Setter Property="Margin" Value="20, 0" />
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="20, 30, 20, 0" />
<Setter Property="FontSize" Value="Large" />
</Style>
</StackLayout.Resources>
<Label Text="Normal Entry:" />
<Entry />
<Label Text="Entry with VSM: " />
<Entry>
<Entry.Triggers>
<DataTrigger TargetType="Entry"
Binding="{Binding Source={x:Reference entry3},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Entry.Triggers>
</Entry>
<Label Text="Entry to enable 2nd Entry:" />
<Entry x:Name="entry3"
Text=""
Placeholder="Type something to enable 2nd Entry" />
</StackLayout>
</ContentPage>
これで、 Entry
このページのすべてのビューが、表示状態に対して同じ方法で応答するようになりました。 また、"Focused" 状態には、入力フォーカスがある場合にも各ライムの背景を与える Entry
2 つ目Setter
が含まれていることに注意してください。
の視覚的な状態 Xamarin.Forms
で定義されている視覚的な状態を次の表に Xamarin.Forms示します。
クラス | 状態 | 詳細情報 |
---|---|---|
Button |
Pressed |
ボタンの表示状態 |
CheckBox |
IsChecked |
CheckBox の表示状態 |
CarouselView |
DefaultItem , CurrentItem , PreviousItem , NextItem |
カルーセルビューの表示状態 |
ImageButton |
Pressed |
ImageButton のビジュアル状態 |
RadioButton |
Checked , Unchecked |
RadioButton の表示状態 |
Switch |
On , Off |
ビジュアルの状態を切り替える |
VisualElement |
Normal , Disabled , Focused , Selected |
一般的な状態 |
これらの各状態には、 という名前 CommonStates
のビジュアル状態グループを介してアクセスできます。
さらに、 は CollectionView
状態を Selected
実装します。 詳細については、「 選択した項目の色を変更する」を参照してください。
複数の要素に状態を設定する
前の例では、視覚的な状態が 1 つの要素にアタッチされ、操作されていました。 ただし、1 つの要素にアタッチされているが、同じスコープ内の他の要素にプロパティを設定する視覚的な状態を作成することもできます。 これにより、状態が動作する各要素で視覚的な状態を繰り返す必要がなくなります。
Setter
型にはTargetName
、 型string
の プロパティがあり、ビジュアル状態の が操作するSetter
ターゲット要素を表します。 プロパティをTargetName
定義すると、 でSetter
定義TargetName
されている要素の が にValue
設定Property
されます。
<Setter TargetName="label"
Property="Label.TextColor"
Value="Red" />
この例では、 という名前label
の Label
は、そのプロパティを TextColor
に設定しますRed
。 プロパティを設定するときは、 TargetName
で Property
プロパティへの完全なパスを指定する必要があります。 したがって、 で Label
Property
プロパティをTextColor
設定するには、 としてLabel.TextColor
指定します。
注意
オブジェクトによって参照されるすべてのプロパティは、 Setter
バインド可能なプロパティによってサポートされている必要があります。
VsmDemos サンプルの VSM with Setter TargetName ページは、1 つのビジュアル状態グループから複数の要素に状態を設定する方法を示しています。 XAML ファイルは、 StackLayout
要素、、 Entry
Button
をLabel
含む で構成されます。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmSetterTargetNamePage"
Title="VSM with Setter TargetName">
<StackLayout Margin="10">
<Label Text="What is the capital of France?" />
<Entry x:Name="entry"
Placeholder="Enter answer" />
<Button Text="Reveal answer">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
<Setter TargetName="entry"
Property="Entry.Text"
Value="Paris" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
</ContentPage>
VSM マークアップは に StackLayout
アタッチされます。 "Normal" と "Pressed" という名前の相互に排他的な状態が 2 つあり、各状態にはタグが VisualState
含まれています。
が押されていない場合 Button
、"Normal" 状態はアクティブであり、質問への応答を入力できます。
が押されると Button
、"Pressed" 状態がアクティブになります。
"Pressed" VisualState
は、 が押されると Button
、その Scale
プロパティが既定値の 1 から 0.8 に変更されることを指定します。 さらに、 という名前entry
の Entry
プロパティは Text
Paris に設定されます。 したがって、結果として、 が押されると Button
、少し小さいサイズに再スケーリングされ、パリが Entry
表示されます。 次に Button
、 が解放されると、既定値の 1 に再スケーリングされ Entry
、以前に入力したテキストが表示されます。
重要
プロパティ パスは、現在、 プロパティを指定TargetName
する要素ではSetter
サポートされていません。
独自のビジュアル状態を定義する
から VisualElement
派生するすべてのクラスは、共通の状態 "Normal"、"Focused"、および "Disabled" をサポートしています。 さらに、 クラスは CollectionView
"Selected" 状態をサポートしています。 内部的には、 クラスは VisualElement
、有効または無効になっているか、フォーカスが設定されているかフォーカスされていない状態になるかを検出し、静的 VisualStateManager.GoToState
メソッドを呼び出します。
VisualStateManager.GoToState(this, "Focused");
これは、 クラスで VisualElement
見つかる唯一の Visual State Manager コードです。 は からVisualElement
派生するすべてのクラスに基づいてすべてのオブジェクトに対して呼び出されるためGoToState
、Visual State Manager を任意VisualElement
のオブジェクトと共に使用して、これらの変更に応答できます。
興味深いことに、ビジュアル状態グループ "CommonStates" の名前は、 で VisualElement
明示的に参照されていません。 グループ名は、Visual State Manager の API の一部ではありません。 これまでに示した 2 つのサンプル プログラムの 1 つ内で、グループの名前を "CommonStates" から他の何かに変更しても、プログラムは引き続き機能します。 グループ名は、そのグループ内の状態の一般的な説明にすぎません。 任意のグループ内のビジュアル状態が相互に排他的であることが暗黙的に理解されます。1 つの状態と、常に 1 つの状態のみが最新です。
独自のビジュアル状態を実装する場合は、コードから を呼び出す VisualStateManager.GoToState
必要があります。 ほとんどの場合、ページ クラスの分離コード ファイルからこの呼び出しを行います。
VsmDemos サンプルの VSM 検証ページは、入力検証に関連して Visual State Manager を使用する方法を示しています。 XAML ファイルは、 StackLayout
と の 2 つの Label
要素を Entry
含む で Button
構成されます。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmValidationPage"
Title="VSM Validation">
<StackLayout x:Name="stackLayout"
Padding="10, 10">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValidityStates">
<VisualState Name="Valid">
<VisualState.Setters>
<Setter TargetName="helpLabel"
Property="Label.TextColor"
Value="Transparent" />
<Setter TargetName="entry"
Property="Entry.BackgroundColor"
Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Invalid">
<VisualState.Setters>
<Setter TargetName="entry"
Property="Entry.BackgroundColor"
Value="Pink" />
<Setter TargetName="submitButton"
Property="Button.IsEnabled"
Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="Enter a U.S. phone number:"
FontSize="Large" />
<Entry x:Name="entry"
Placeholder="555-555-5555"
FontSize="Large"
Margin="30, 0, 0, 0"
TextChanged="OnTextChanged" />
<Label x:Name="helpLabel"
Text="Phone number must be of the form 555-555-5555, and not begin with a 0 or 1" />
<Button x:Name="submitButton"
Text="Submit"
FontSize="Large"
Margin="0, 20"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
VSM マークアップは、 (という名前stackLayout
) にStackLayout
アタッチされます。 "Valid" と "Invalid" という名前の相互に排他的な状態が 2 つあり、各状態にはタグが VisualState
含まれています。
に Entry
有効な電話番号が含まれていない場合、現在の状態は "無効" であるため Entry
、 はピンク色の背景を持ち、2 つ目 Label
は表示され Button
、 は無効になります。
有効な電話番号を入力すると、現在の状態は "有効" になります。 は Entry
ライムの背景を取得し、2 つ目 Label
は消え Button
、 が有効になりました。
分離コード ファイルは、 からのイベントを TextChanged
処理します Entry
。 ハンドラーは正規表現を使用して、入力文字列が有効かどうかを判断します。 という名前 GoToState
の分離コード ファイル内の メソッドは、 の静的 VisualStateManager.GoToState
メソッドを stackLayout
呼び出します。
public partial class VsmValidationPage : ContentPage
{
public VsmValidationPage()
{
InitializeComponent();
GoToState(false);
}
void OnTextChanged(object sender, TextChangedEventArgs args)
{
bool isValid = Regex.IsMatch(args.NewTextValue, @"^[2-9]\d{2}-\d{3}-\d{4}$");
GoToState(isValid);
}
void GoToState(bool isValid)
{
string visualState = isValid ? "Valid" : "Invalid";
VisualStateManager.GoToState(stackLayout, visualState);
}
}
状態を GoToState
初期化するために、 メソッドがコンストラクターから呼び出されていることにも注意してください。 常に現在の状態が存在する必要があります。 ただし、わかりやすくするために XAML で "ValidationStates" として参照されていますが、コード内のどこにもビジュアル状態グループの名前への参照はありません。
分離コード ファイルでは、表示状態を定義するページ上の オブジェクトのみを考慮し、このオブジェクトを呼び出す VisualStateManager.GoToState
必要があることに注意してください。 これは、両方のビジュアル状態がページ上の複数のオブジェクトを対象としているためです。
疑問に思うかもしれません。分離コード ファイルが、視覚的な状態を定義するページ上のオブジェクトを参照する必要がある場合、分離コード ファイルでこれと他のオブジェクトに直接アクセスできないのはなぜですか? それは確かにできる。 ただし、VSM を使用する利点は、ビジュアル要素が XAML で異なる状態に完全に反応する方法を制御できることです。これにより、すべての UI デザインが 1 つの場所に保持されます。 これにより、分離コードからビジュアル要素に直接アクセスして、視覚的な外観を設定できなくなります。
ビジュアル状態トリガー
ビジュアル状態では、状態トリガーがサポートされます。これは、 を適用する条件を定義する VisualState
特殊なトリガーのグループです。
状態トリガーは、VisualState
の StateTriggers
コレクションに追加されます。 このコレクションには、1 つの状態トリガーを含めることも、複数の状態トリガーを含めることもできます。 コレクション内のいずれかの状態トリガーがアクティブになっていると、VisualState
が適用されます。
状態トリガーを使用してビジュアルの状態を制御する場合、Xamarin.Forms では、アクティブにするトリガー (および対応する VisualState
) を決定するために、次の優先順位規則が使用されます。
StateTriggerBase
から派生したトリガー。MinWindowWidth
条件の適用によってアクティブにされたAdaptiveTrigger
。MinWindowHeight
条件の適用によってアクティブにされたAdaptiveTrigger
。
複数のトリガーが同時にアクティブにされた場合 (たとえば、2 つのカスタム トリガー)、マークアップで最初に宣言されたトリガーが優先されます。
状態トリガーの詳細については、「状態トリガー」を参照してください。
アダプティブ レイアウトに Visual State Manager を使用する
Xamarin.Forms通常、電話で実行されているアプリケーションは縦または横の縦横比で表示でき、Xamarin.Formsデスクトップで実行されているプログラムのサイズを変更して、さまざまなサイズと縦横比を想定できます。 適切に設計されたアプリケーションでは、これらのさまざまなページフォームファクターまたはウィンドウフォームファクターに対してコンテンツが異なる方法で表示される場合があります。
この手法は 、アダプティブ レイアウトと呼ばれることもあります。 アダプティブ レイアウトにはプログラムのビジュアルのみが含まれるため、Visual State Manager の理想的なアプリケーションです。
簡単な例は、アプリケーションのコンテンツに影響を与えるボタンの小さなコレクションを表示するアプリケーションです。 縦モードでは、これらのボタンはページの上部の水平行に表示される場合があります。
横モードでは、ボタンの配列が一方の側に移動され、列に表示されることがあります。
上から下へ、プログラムはユニバーサル Windows プラットフォーム、Android、iOS で実行されています。
VsmDemos サンプルの VSM アダプティブ レイアウト ページでは、"OrientationStates" という名前のグループが定義され、"Portrait" と "Landscape" という名前の 2 つのビジュアル状態が定義されています。 (より複雑なアプローチは、複数の異なるページまたはウィンドウの幅に基づいている場合があります)。
VSM マークアップは、XAML ファイル内の 4 つの場所で発生します。 名前付き mainStack
にはStackLayout
、メニューとコンテンツ (要素) の両方がImage
含まれています。 縦 StackLayout
モードでは垂直方向、横向きモードでは水平方向である必要があります。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmAdaptiveLayoutPage"
Title="VSM Adaptive Layout">
<StackLayout x:Name="mainStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ScrollView x:Name="menuScroll">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout x:Name="menuStack">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout.Resources>
<Style TargetType="Button">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="OrientationStates">
<VisualState Name="Portrait">
<VisualState.Setters>
<Setter Property="HorizontalOptions" Value="CenterAndExpand" />
<Setter Property="Margin" Value="10, 5" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Landscape">
<VisualState.Setters>
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="Margin" Value="10" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</StackLayout.Resources>
<Button Text="Banana"
Command="{Binding SelectedCommand}"
CommandParameter="Banana.jpg" />
<Button Text="Face Palm"
Command="{Binding SelectedCommand}"
CommandParameter="FacePalm.jpg" />
<Button Text="Monkey"
Command="{Binding SelectedCommand}"
CommandParameter="monkey.png" />
<Button Text="Seated Monkey"
Command="{Binding SelectedCommand}"
CommandParameter="SeatedMonkey.jpg" />
</StackLayout>
</ScrollView>
<Image x:Name="image"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>
ScrollView
内部の 名前付き menuScroll
と 名前付き menuStack
はStackLayout
、ボタンのメニューを実装します。 これらのレイアウトの向きは、 の反対です mainStack
。 縦モードではメニューは水平、横モードでは垂直にする必要があります。
VSM マークアップの 4 番目のセクションは、ボタン自体の暗黙的なスタイルです。 このマークアップは、縦向きとMargin
横向きに固有の 、HorizontalOptions
、および プロパティを設定VerticalOptions
します。
分離コード ファイルは、 の プロパティmenuStack
をBindingContext
設定してコマンドを実装Button
し、ページの イベントにもSizeChanged
ハンドラーをアタッチします。
public partial class VsmAdaptiveLayoutPage : ContentPage
{
public VsmAdaptiveLayoutPage ()
{
InitializeComponent ();
SizeChanged += (sender, args) =>
{
string visualState = Width > Height ? "Landscape" : "Portrait";
VisualStateManager.GoToState(mainStack, visualState);
VisualStateManager.GoToState(menuScroll, visualState);
VisualStateManager.GoToState(menuStack, visualState);
foreach (View child in menuStack.Children)
{
VisualStateManager.GoToState(child, visualState);
}
};
SelectedCommand = new Command<string>((filename) =>
{
image.Source = ImageSource.FromResource("VsmDemos.Images." + filename);
});
menuStack.BindingContext = this;
}
public ICommand SelectedCommand { private set; get; }
}
ハンドラーは SizeChanged
2 つの StackLayout
要素と ScrollView
要素を呼び出VisualStateManager.GoToState
し、 のmenuStack
子をループ処理して 要素をButton
呼び出VisualStateManager.GoToState
します。
分離コード ファイルで XAML ファイル内の要素のプロパティを設定することで方向の変更をより直接処理できるように見えるかもしれませんが、Visual State Manager は間違いなくより構造化されたアプローチです。 すべてのビジュアルは XAML ファイルに保持され、検査、保守、変更が容易になります。
Xamarin.University を使用した Visual State Manager
Xamarin.Forms 3.0 Visual State Manager のビデオ