読者です 読者をやめる 読者になる 読者になる

酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

WindowsストアアプリでGridViewのアイテムごとにタップしたエフェクトアニメーションを実行させるかどうか決めたい

かずき( id:okazuki )さんに「WindowsストアアプリのGridViewでタイルをタップした時に押した時のチルトエフェクトアニメが動いちゃうんですけど、アイテムごとにアニメするかしないか決めたいんですよ」と、何かのプロパティを変更するいいんでしょ?的なノリで話をしました。

iOSのUITableViewでセルを返す時には、セルの選択状態を青色や灰色のする場合にUITableViewCellクラスのselectionStyleプロパティの値を変更します。

- (UITableViewCell *)tableView:(UITableView *)tableView 
            cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  static NSString *CellIdentifier = @"Cell";
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
  }
  return cell;
}

今回やりたかったことは、セル単位で選択しない状態にする cell.selectionStyle = UITableViewCellSelectionStyleNone; をWindowsストアアプリでやりたかったのです。これをかずき( id:okazuki )さんがこのように書いてくださいました。

上記の記事を参考にして、僕の方でも実装してみました。

かずきさんの記事では、タップしたときにアニメーションさせる普通のスタイルGridViewItemStyleとアニメーションさせないスタイルNoSwipeAnimationGridViewItemStyleのスタイルを定義して、セレクターItemContainerStyleSelectorによってどちらのスタイルを使用するか決めています。重要なのは下記の要素です。

  • GridViewアイテムを押したした時にアニメーションさせる普通のスタイル
    • GridViewItemStyle
  • GridViewアイテムを押したした時にアニメーションさせないスタイル
    • NoSwipeAnimationGridViewItemStyle
  • どちらのスタイルを使用するかを決定するセレクター
    • ItemContainerStyleSelector

ItemContainerStyleSelectorを実装する

プロジェクトにGridViewItemContainerStyleSelector.csを新規追加して、以下のようにセレクターを書きます(かずきさんのソースコードをコピペしただけです)。

どんなアイテムが来ても大丈夫なようにクラス変数にcountを持たせて、奇数であればOddStyleプロパティに登録されたスタイルが適用され、countの値が偶数であればEvenStyleプロパティに登録されたスタイルが適用されます。

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace NoPushSample
{
    public class GridViewItemContainerStyleSelector : StyleSelector
    {
        /// <summary>
        /// 奇数の値用スタイル
        /// </summary>
        public Style OddStyle { get; set; }

        /// <summary>
        /// 偶数の値用スタイル
        /// </summary>
        public Style EvenStyle { get; set; }

        static int count;

        protected override Style SelectStyleCore(object item, 
                    DependencyObject container)
        {
            count++;

            return (count % 2 == 0) ? EvenStyle : OddStyle;
        }
    }
}

XAML側のGroupedItemsPageを実装する

XAML側でGridViewItemStyleNoSwipeAnimationGridViewItemStyleのスタイルを定義します。

GirdViewを選択して、右クリックしてコンテキストメニューから「追加テンプレートの編集」、「生成されたアイテムコンテナーの編集(ItemContainerStyle)」、「コピーして編集」の順に選択します。

f:id:ch3cooh393:20140202131248p:plain

新しく作成するItemContainerStyleの名前を何にするかを決めます。ここではGridViewItemStyleという名前を付けました。このスタイルはチルトエフェクトさせないスタイルです。

f:id:ch3cooh393:20140202131146p:plain

NoSwipeAnimationGridViewItemStyleは、かずきさんのブログからコピペしました。

        <!-- GridViewアイテムを押したした時にアニメーションさせないスタイル -->
        <Style x:Key="NoSwipeAnimationGridViewItemStyle" TargetType="GridViewItem">
            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
            <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="TabNavigation" Value="Local"/>
            <Setter Property="IsHoldingEnabled" Value="True"/>
            <Setter Property="Margin" Value="0,0,2,2"/>
            <Setter Property="Padding" Value="4"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GridViewItem">
                        <Border Padding="{TemplateBinding Padding}">
                            <ContentPresenter />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- GridViewアイテムを押したした時にアニメーションさせる普通のスタイル -->
        <Style x:Key="GridViewItemStyle" TargetType="GridViewItem">
            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
            <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="TabNavigation" Value="Local"/>
            <Setter Property="IsHoldingEnabled" Value="True"/>
            <Setter Property="Margin" Value="0,0,2,2"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GridViewItem">
                        <GridViewItemPresenter CheckHintBrush="{ThemeResource ListViewItemCheckHintThemeBrush}" 
                           CheckBrush="{ThemeResource ListViewItemCheckThemeBrush}" 
                           ContentMargin="4" ContentTransitions="{TemplateBinding ContentTransitions}" 
                           CheckSelectingBrush="{ThemeResource ListViewItemCheckSelectingThemeBrush}" 
                           DragForeground="{ThemeResource ListViewItemDragForegroundThemeBrush}" 
                           DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}" 
                           DragBackground="{ThemeResource ListViewItemDragBackgroundThemeBrush}" 
                           DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}" 
                           FocusBorderBrush="{ThemeResource ListViewItemFocusBorderThemeBrush}" 
                           HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
                           Padding="{TemplateBinding Padding}" PointerOverBackgroundMargin="1" 
                           PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" 
                           PointerOverBackground="{ThemeResource ListViewItemPointerOverBackgroundThemeBrush}" 
                           ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" 
                           SelectedPointerOverBorderBrush="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}" 
                           SelectionCheckMarkVisualEnabled="True" 
                           SelectedForeground="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" 
                           SelectedPointerOverBackground="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}" 
                           SelectedBorderThickness="{ThemeResource GridViewItemCompactSelectedBorderThemeThickness}" 
                           SelectedBackground="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}" 
                           VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- アイテムごとにどのスタイルを適用するかを決定するセレクター -->
        <local:GridViewItemContainerStyleSelector x:Key="itemContainerStyleSelector" 
            OddStyle="{StaticResource GridViewItemStyle}"
            EvenStyle="{StaticResource NoSwipeAnimationGridViewItemStyle}"/>

上記で定義したスタイルとスタイルセレクターを、下記のようにGridViewへ適用します。

        <!-- 水平スクロール グリッド -->
        <GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Grouped Items"
            Grid.RowSpan="2"
            Padding="116,137,40,46"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            SelectionMode="None"
            IsSwipeEnabled="false"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick"
            ItemTemplate="{StaticResource GridViewItemTemplate}"
            ItemContainerStyleSelector="{StaticResource itemContainerStyleSelector}" >
            
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid GroupPadding="0,0,70,0"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            
            <GridView.GroupStyle>
                <GroupStyle HeaderTemplate="{StaticResource GridViewHeaderTemplate}" />
            </GridView.GroupStyle>
        </GridView>

以上で、できあがったのが下図のようなアプリです。見た目はテンプレートそのままのアプリですが「選択できるアイテム」「選択できないアイテム」が順々に表示されます。

f:id:ch3cooh393:20140202132156p:plain

関係ない要素が多かったので、ここでは重要な部分をXAMLから切り張りしています。手を入れたXAMLをみたいという方は、こちらをご覧ください。