モーダルダイアログ風なものができたので、これを応用して自動的に閉じるダイアログを作ります。
のようにメッセージを表示して、しばらくしたら閉じるっていうメッセージダイアログです。よくゲームであるパターンだし、他のアプリでも応用が利きます。
フォームアプリの場合にはタイマーを使ってイベント待ちをするのが定番ですが、WinRT の場合(というか XAMLの場合)には、storyboard を使って、3秒後の閉じる、ってのがコード的に楽です。
自動的に閉じるダイアログは、Popup でも Canvas でもいいのですが、ここでは、popup を使って実現してみます。
■popup でダイアログを作る
popup コントロールを使って、ダイアログを作成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | < 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 を使って作ります。
1 2 3 4 5 6 7 8 9 10 | < 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 で閉じておくこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /// <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 などのメソッドは即時実行されます。さきゆきは、場からマッチしたときのアニメーションも追加するので、このあたりの整合性(画面の動き的な整合性)をあわせる必要がありますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /// <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 を追加してみたのですが呼び出されませんでした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | < 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 メソッドを使って最終点まで移動させます。これでタップしたときには即時終了します。
1 2 3 4 5 6 7 8 9 | /// <summary> /// ポップアップをタップした時 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void popClick( object sender, TappedRoutedEventArgs e) { this .sbPopYaku.SkipToFill(); } |
他のアニメーションとの整合性もあるのですが(札を手持ちに加えるアニメーションとか)、ひとまず役をできたときのポップアップはこれで ok ということで。