だるろぐ

明日できることは、今日しない。

WinRT/XAML のお勉強 ―― 4つの表示状態

Windows ストアアプリには4つの状態(VisualState)がある

  • FullScreenLandscape:全画面表示(横)
  • FullScreenPortrait:全画面表示(縦)
  • Snapped:端に寄せる(幅300px)
  • Filled:ほかのアプリを Snap した残りの領域に表示

これを一つのデザインで対応しようとするととても難しい、という話が前回(WinRT/XAML のお勉強 ―― さまざまな利用シーンに対応する - だるろぐ)だった。あれからいろいろ試したんだけれど、ひとつのデザインですべてをカバーしようとするより、4つの VisualState にそれぞれ個別にデザインを作って割り当てたほうがよさそうだ*1

じゃぁ、VisualState によってビューを切り替えるのってどうすればいいんだ? ってのが今日の主題。

<Grid Style="{StaticResource LayoutRootStyle}">
    <Grid.RowDefinitions>
        <RowDefinition Height="140"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!-- Back button and page title -->
    <Grid>
        (ヘッダー。内容省略)
    </Grid>

    <Grid x:Name="FullScreenLandscapeGrid" 
          Grid.Row="1" Background="Blue" />
    <Grid x:Name="FullScreenPortraitGrid"
          Grid.Row="1" Background="Yellow" Visibility="Collapsed" />
    <Grid x:Name="SnappedGrid"
          Grid.Row="1" Background="Green" Visibility="Collapsed" />
    <Grid x:Name="FilledGrid"
          Grid.Row="1" Background="Red" Visibility="Collapsed" />

こうやって VisualState に対応する Grid を用意する(名前でわかるよね!)。わかりやすくセンスの悪い背景色をそれぞれ割り当てておいた。Grid.Row="1" なのはヘッダー(Grid.Row[0])の下に表示するためやね。

で、初期状態の FullScreenLandscape 以外は非表示(Visibility="Collapsed")にしておく。あとは、最後のほうにある のところで、表示非表示を切り替えるだけ。

<VisualStateManager.VisualStateGroups>
    <!-- Visual states reflect the application's view state -->
    <VisualStateGroup x:Name="ApplicationViewStates">
        <VisualState x:Name="FullScreenLandscape">
             (初期表示なので別に何もしないでいい感じ)
        </VisualState>

        <!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
        // 全画面(横向きになったら……)
        <VisualState x:Name="FullScreenPortrait">
            <Storyboard>
                (関係のないところ省略)

                // FullScreenLandscapeGrid を非表示に
                <ObjectAnimationUsingKeyFrames
                    Storyboard.TargetName="FullScreenLandscapeGrid"
                    Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame
                        KeyTime="0" Value="Collapsed"/>
                </ObjectAnimationUsingKeyFrames>

                // FullScreenPortraitGrid を表示に
                <ObjectAnimationUsingKeyFrames
                    Storyboard.TargetName="FullScreenPortraitGrid"
                    Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame
                        KeyTime="0" Value="Visible"/>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </VisualState>

        // Filled になったら……
        <VisualState x:Name="Filled">
        :
        : (以下略)

結果はこんな感じ。

FullScreenLandscape

f:id:daruyanagi:20120920231821p:plain

FullScreenPortrait

f:id:daruyanagi:20120920231828p:plain

FullScreenLandscapeGrid.Visibility -> Collapsed
FullScreenPortraitGrid.Visibility -> Visible

Snapped

f:id:daruyanagi:20120920231839p:plain

FullScreenLandscapeGrid.Visibility -> Collapsed
SnappedGrid.Visibility -> Visible

Filled

f:id:daruyanagi:20120920231848p:plain

FullScreenLandscapeGrid.Visibility -> Collapsed
FilledGrid.Visibility -> Visible

あとはそれぞれ、解像度が変わる場合をよく考えながらデザインしていけばいいと思う。まぁ、なるべくテンプレ使うのがよさそうだけど、ちょっと試してみたところ、自分の目的には合わない気がしたのでやっぱこれで行こうと思う。

余談

ここまでやるのはそんなに難しくなかったけど、途中、シミュレーターの回転に異様に時間がかかり、いろんなエラーをはいてしまってちょっと躓いた。再起動でなおったけど……。最初は自分のソースが悪かったのかなぁと思ってあちこち直してたのだけど、結局新規にページを作ってもエラーが出るので、やっとシミュレーターがおかしいんだってわかった。

まぁ、そんなこともあるよね。

*1:ただ、FullScreenLandscape と Filled はとてもよく似ているので、分ける必要はないかもしれない