しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

ウィンドウ幅に応じて列数が変化する GridView

普通はクロススライド(タイルをスクロール方向に交差する下にドラッグさせる)で項目を選択するため原則水平スクロールにするんですが、どうしても!GridView を縦スクロールしたい・・・という場合どうしたらよいか

f:id:matatabi_ux:20140628200306p:plain

その場合はウィンドウ幅に応じて列数をレスポンシブに変化させる必要があります

そんな GridView の表示の仕方を作ってみました

まずは XAML の記述

<!--  水平スクロール グリッド  -->
<GridView x:Name="itemGridView"
            Grid.Row="1"
            Grid.RowSpan="1"
            AutomationProperties.AutomationId="ItemsGridView"
            AutomationProperties.Name="Items"
            IsItemClickEnabled="True"
            IsSwipeEnabled="false"
            ItemClick="Presenter.OnItemClick"
            ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
            Padding="0"
            ScrollViewer.HorizontalScrollBarVisibility="Disabled"
            ScrollViewer.HorizontalScrollMode="Disabled"
            ScrollViewer.VerticalScrollBarVisibility="Auto"
            ScrollViewer.VerticalScrollMode="Auto"
            SelectionMode="None"
            TabIndex="1">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VariableSizedWrapGrid Margin="116,0,76,76"
                                    ItemHeight="250"
                                    ItemWidth="285"
                                    Orientation="Horizontal"
                                    SizeChanged="Presenter.OnVariableSizedWrapGridSizeChanged" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    <GridView.ItemContainerStyle>
        <Style TargetType="GridViewItem">
            <Setter Property="Margin" Value="0,0,20,20" />
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="VerticalContentAlignment" Value="Stretch" />
        </Style>
    </GridView.ItemContainerStyle>
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Image HorizontalAlignment="Center"
                        VerticalAlignment="Top"
                        AutomationProperties.Name="{Binding Content.Title}"
                        Source="{Binding Content.ImageUri}"
                        Stretch="UniformToFill" />
                <Border VerticalAlignment="Bottom"
                        Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}"
                        Padding="15">
                    <TextBlock FontSize="18"
                                Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}"
                                Style="{StaticResource BaseTextBlockStyle}"
                                TextTrimming="CharacterEllipsis"
                                TextWrapping="NoWrap">
                        <Run Text="Photo: " /><Run Text="{Binding Content.Title}" /><Run Text=" by " /><Run Text="{Binding Content.Owner}" />
                    </TextBlock>
                </Border>
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

GridView.ItemsPanel に VariableSizedWrapGrid を指定して Orientation に Horizontal を指定しているのと、SizeChanged イベントハンドラを追加しました それ以外はいたって普通の GridView の記述です

次に SizeChanged イベントハンドラの中身を記述します

/// <summary>
/// GridView 内部の VariableSizedWrapGrid のサイズ変更イベントハンドラ
/// </summary>
/// <param name="sender">イベント発行者</param>
/// <param name="e">イベント引数</param>
public void OnVariableSizedWrapGridSizeChanged(object sender, SizeChangedEventArgs e)
{
    var wrapGrid = sender as VariableSizedWrapGrid;
    if (wrapGrid == null)
    {
        return;
    }

    switch (wrapGrid.Orientation)
    {
        // Z字型の並び順の場合
        case Orientation.Horizontal:
            wrapGrid.MaximumRowsOrColumns = (int)Math.Floor(e.NewSize.Width / wrapGrid.ItemWidth);
            break;

        // И字型の並び順の場合
        case Orientation.Vertical:
            wrapGrid.MaximumRowsOrColumns = (int)Math.Floor(e.NewSize.Height / wrapGrid.ItemHeight);
            break;
    }
}

VariableSizedWrapGrid をキャストで参照後、Orientation の設定に応じて VariableSizedWrapGrid.MaximumRowsOrColumns の値を切り替えています

VariableSizedWrapGrid.MaximumRowsOrColumns は表示される最大列数もしくは最大行数で Orientation の設定応じて最大列数か最大行数として扱われるかが変わります

新しい MaximumRowsOrColumns の値は ItemWidth や ItemHeight で新たな VariableSizedWrapGrid の Width や Height を割った切り捨て値を指定しているだけです

f:id:matatabi_ux:20140628202251p:plain

これだけでできました!簡単ですね