モーダルダイアログ風なものができたので、これを応用して自動的に閉じるダイアログを作ります。
のようにメッセージを表示して、しばらくしたら閉じるっていうメッセージダイアログです。よくゲームであるパターンだし、他のアプリでも応用が利きます。
フォームアプリの場合にはタイマーを使ってイベント待ちをするのが定番ですが、WinRT の場合(というか XAMLの場合)には、storyboard を使って、3秒後の閉じる、ってのがコード的に楽です。
自動的に閉じるダイアログは、Popup でも Canvas でもいいのですが、ここでは、popup を使って実現してみます。
■popup でダイアログを作る
popup コントロールを使って、ダイアログを作成。
<Popup x:Name="popYaku" Margin="320,160,-320,328" Grid.Row="1"> <Grid Background="Red" Height="213" Width="399"> <TextBlock x:Name="popYakuText" FontSize="40" HorizontalAlignment="Left" Margin="34,32,0,0" TextWrapping="Wrap" Text="役ができました" VerticalAlignment="Top"/> <Image x:Name="pictYaku1" HorizontalAlignment="Left" Height="100" Margin="34,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku2" HorizontalAlignment="Left" Height="100" Margin="103,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku3" HorizontalAlignment="Left" Height="100" Margin="172,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku4" HorizontalAlignment="Left" Height="100" Margin="241,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku5" HorizontalAlignment="Left" Height="100" Margin="310,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> </Grid> </Popup>
この場合には、花札の役を表示するので、あらかじめ image コントロールを貼り付けておきます。
■blend で storyboard を追加する
3秒経ったらダイアログを閉じるタイムラインを、blend を使って作ります。
<Page.Resources> <!-- TODO: Delete this line if the key AppName is declared in App.xaml --> <x:String x:Key="AppName">花札 こいこい</x:String> <Storyboard x:Name="sbPopYaku"> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="popYaku"> <EasingDoubleKeyFrame KeyTime="0:0:2.5" Value="1"/> <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </Page.Resources>
プログラムから storyboard を起動するので名前をつけておくのと、単に消えると WinRT らしくないので、最後の 0.5 秒だけは透明度を変更するという方式にします。この手のアニメーションは blend を使うとひじょうに楽ですね。
■アニメーション終了時の処理を追加
ポップアップを開くときは、IsOpen プロパティを true にすれば ok。ストリーボードの開始は sbPopYaku.Begin() な感じで実行ができます。
で、忘れちゃいけないのが、アニメーションが終了した時に、ストリーボードを Stop で終了させておくことと、ポップアップを IsOpen = false で閉じておくこと。
/// <summary> /// 役を表示 /// </summary> /// <param name="y"></param> void dispPopYaku( Yaku y ) { this.pictYaku1.Visibility = Windows.UI.Xaml.Visibility.Visible; this.pictYaku2.Visibility = Windows.UI.Xaml.Visibility.Visible; this.pictYaku3.Visibility = Windows.UI.Xaml.Visibility.Visible; this.pictYaku4.Visibility = Windows.UI.Xaml.Visibility.Visible; this.pictYaku5.Visibility = Windows.UI.Xaml.Visibility.Visible; if (y.GoKou != null) { this.popYakuText.Text = "五光"; this.pictYaku1.Source = CardUI.GetResName(y.GoKou[0].ID); this.pictYaku2.Source = CardUI.GetResName(y.GoKou[1].ID); this.pictYaku3.Source = CardUI.GetResName(y.GoKou[2].ID); this.pictYaku4.Source = CardUI.GetResName(y.GoKou[3].ID); this.pictYaku5.Source = CardUI.GetResName(y.GoKou[4].ID); } // 略 this.sbPopYaku.Completed += sbPopYaku_Completed; this.popYaku.IsOpen = true; this.sbPopYaku.Begin(); } /// <summary> /// タイマー完了時 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void sbPopYaku_Completed(object sender, object e) { this.sbPopYaku.Stop(); this.popYaku.IsOpen = false; }
これで、適当なところで dispPopYaku メソッドを呼び出せばポップアップが表示されます。
アニメーションは非同期で行われるので、下記のように、dispPopYaku でポップアップを表示させた後は、_curPlayer.GetCard などのメソッドは即時実行されます。さきゆきは、場からマッチしたときのアニメーションも追加するので、このあたりの整合性(画面の動き的な整合性)をあわせる必要がありますね。
/// <summary> /// 場に出した札をクリックしてマッチさせる /// </summary> /// <param name="obj"></param> void baControl1_ClickPutCard(Card obj) { var lst = _board.Game.MatchBa(_board.Ba, _board.Ba.PlayerCard, _curPlayer); if (lst != null) { // カードが決定した場合、画面を更新 _board.Ba.GetCard(lst); // 役の計算 Yaku y = _board.Game.CalcYaku(lst, _curPlayer.TakenCards); if (y != null) { // 一定時間、役を表示 dispPopYaku(y); } // 手持ちに加える _curPlayer.GetCard(lst); // 画面の更新 ScrUpdate(); } }
■ダイアログをタップした瞬時の閉じる処理を追加
自動的にポップアップは閉じるのですが、タップしたときに即時終了させる処理も追加しておきます。
ポップアップの grid 部分に Tapeed イベントを追加しておきます。ためしに Popup 自身に Tapped を追加してみたのですが呼び出されませんでした。
<Popup x:Name="popYaku" Margin="320,160,-320,328" Grid.Row="1"> <Grid Background="Red" Height="213" Width="399" Tapped="popClick" > <TextBlock x:Name="popYakuText" FontSize="40" HorizontalAlignment="Left" Margin="34,32,0,0" TextWrapping="Wrap" Text="役ができました" VerticalAlignment="Top"/> <Image x:Name="pictYaku1" HorizontalAlignment="Left" Height="100" Margin="34,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku2" HorizontalAlignment="Left" Height="100" Margin="103,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku3" HorizontalAlignment="Left" Height="100" Margin="172,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku4" HorizontalAlignment="Left" Height="100" Margin="241,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> <Image x:Name="pictYaku5" HorizontalAlignment="Left" Height="100" Margin="310,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/> </Grid> </Popup>
アニメーションの完了イベントを発生させるために、SkipToFill メソッドを使って最終点まで移動させます。これでタップしたときには即時終了します。
/// <summary> /// ポップアップをタップした時 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void popClick(object sender, TappedRoutedEventArgs e) { this.sbPopYaku.SkipToFill(); }
他のアニメーションとの整合性もあるのですが(札を手持ちに加えるアニメーションとか)、ひとまず役をできたときのポップアップはこれで ok ということで。