Connected Animation というものを使うと出来ます。
ConnectedAnimationService.GetForCurrentView() で取得した ConnectedAnimationService に対して画面遷移前と画面遷移後で対応するコントロールの紐づけをしてやる感じです。なので、画面遷移前に画面遷移前のページでアニメーションさせたいコントロールを登録して、画面遷移先でもアニメーションさせたいコントロールを指示するという処理が必要になります。
こんなイメージです。
// 画面遷移前 var a = ConnectedAnimationService.GetForCurrentView(); a.PrepareToAnimate("text", textBlock); a.PrepareToAnimate("button", button); Frame.Navigate(typeof(NextPage)); // 画面遷移先の OnNavigatedTo メソッドにて var a = ConnectedAnimationService.GetForCurrentView(); a.GetAnimation("text")?.TryStart(textBlock); a.GetAnimation("button")?.TryStart(button);
PrepareToAnimate や TryStart に渡してるのがアニメーションさせたいコントロールです。こんな感じで動きます。
ListView の要素でアニメーション
普通は ListView タップしたら詳細画面に行くってパターンが多いですよね。そのときしゅっとアニメーションしたらかっこいい…!やってみよう。
データの入れ物作ります。
publicclass Person { publicstring Id { get; set; } = Guid.NewGuid().ToString(); publicstring Name { get; set; } }
とりあえずお試しなので App クラスあたりにグローバルでリスト持たせておきましょう。
publicstatic Person[] People { get; } = Enumerable.Range(1, 100) .Select(x => new Person { Name = $"tanaka-{x}", }) .ToArray();
MainPage.xaml で以下のようにバインドします。
<Page x:Class="App14.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App14"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><ListView x:Name="listView"><ListView.ItemTemplate><DataTemplate x:DataType="local:Person"><Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><TextBlock x:Name="textBlockName"Text="{x:Bind Name}"Style="{ThemeResource BodyTextBlockStyle}" /><Border x:Name="border"Background="Red"Width="50"Height="50"Margin="5"Grid.Column="1" /></Grid></DataTemplate></ListView.ItemTemplate></ListView></Grid></Page>
コードビハインドでデータを ListView に追加しておきます。
using Windows.UI.Xaml.Controls; // 空白ページの項目テンプレートについては、https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x411 を参照してくださいnamespace App14 { /// <summary>/// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。/// </summary>publicsealedpartialclass MainPage : Page { public MainPage() { this.InitializeComponent(); listView.ItemsSource = App.People; } } }
ListView を押したら画面遷移するようにします。ItemClick イベントを拾って
<ListView x:Name="listView"IsItemClickEnabled="True"SelectionMode="None"ItemClick="listView_ItemClick">
ListView の PrepareConnectedAnimation で下準備して画面遷移します。
privatevoid listView_ItemClick(object sender, ItemClickEventArgs e) { listView.PrepareConnectedAnimation("text", e.ClickedItem, "textBlockName"); listView.PrepareConnectedAnimation("border", e.ClickedItem, "border"); Frame.Navigate(typeof(NextPage), ((Person)e.ClickedItem).Id); }
遷移先のページを作ります。
<Page x:Class="App14.NextPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App14"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><StackPanel VerticalAlignment="Center"HorizontalAlignment="Center"><TextBlock x:Name="textBlock"Style="{ThemeResource HeaderTextBlockStyle}" /><Border x:Name="border"Width="100"Height="100"Background="Red" /></StackPanel><Button x:Name="button"Content="Back"Click="Button_Click" /></Grid></Page>
OnNavigatedTo メソッドでアニメーションの紐づけを行います。
private Person _target; protectedoverridevoid OnNavigatedTo(NavigationEventArgs e) { _target = App.People.First(x => x.Id == (string)e.Parameter); textBlock.Text = _target.Name; var a = ConnectedAnimationService.GetForCurrentView(); a.GetAnimation("text")?.TryStart(textBlock); a.GetAnimation("border")?.TryStart(border); }
戻る方向もアニメーションをつけます。遷移先のページから戻る前にアニメーションの下準備をして…
privatevoid Button_Click(object sender, RoutedEventArgs e) { var a = ConnectedAnimationService.GetForCurrentView(); a.PrepareToAnimate("text", textBlock); a.PrepareToAnimate("border", border); Frame.Navigate(typeof(MainPage), _target.Id); }
戻った先でアニメーションを開始します。
<Page x:Class="App14.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App14"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><ListView x:Name="listView"IsItemClickEnabled="True"SelectionMode="None"ItemClick="listView_ItemClick"Loaded="listView_Loaded"><ListView.ItemTemplate><DataTemplate x:DataType="local:Person"><Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><TextBlock x:Name="textBlockName"Text="{x:Bind Name}"Style="{ThemeResource BodyTextBlockStyle}" /><Border x:Name="border"Background="Red"Width="50"Height="50"Margin="5"Grid.Column="1" /></Grid></DataTemplate></ListView.ItemTemplate></ListView></Grid></Page>
using System; using System.Linq; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Navigation; // 空白ページの項目テンプレートについては、https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x411 を参照してくださいnamespace App14 { /// <summary>/// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。/// </summary>publicsealedpartialclass MainPage : Page { public MainPage() { this.InitializeComponent(); listView.ItemsSource = App.People; } private Person _scrollTarget; protectedoverridevoid OnNavigatedTo(NavigationEventArgs e) { if (e.Parameter isstring id) { _scrollTarget = App.People.FirstOrDefault(x => x.Id == id); } } privatevoid listView_ItemClick(object sender, ItemClickEventArgs e) { listView.PrepareConnectedAnimation("text", e.ClickedItem, "textBlockName"); listView.PrepareConnectedAnimation("border", e.ClickedItem, "border"); Frame.Navigate(typeof(NextPage), ((Person)e.ClickedItem).Id); } private async void listView_Loaded(object sender, RoutedEventArgs e) { if (_scrollTarget == null) { return; } listView.ScrollIntoView(_scrollTarget); await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => { var a = ConnectedAnimationService.GetForCurrentView(); await Task.WhenAll( listView.TryStartConnectedAnimationAsync(a.GetAnimation("text"), _scrollTarget, "textBlockName").AsTask(), listView.TryStartConnectedAnimationAsync(a.GetAnimation("border"), _scrollTarget, "border").AsTask()); }); } } }
ポイントは ListView の Loaded イベントでアニメーションをしていることです。 OnNavigatedTo だとタイミングが早すぎるのか例外が出てしまいました。
そして、ListView で表示対象のコントロールが出てくるまでスクロールしてアニメーションをしています。アニメーションは、Dispatcher を使って少し遅らせてやってます。これをしないと自分のところではアニメーションしてくれなかった…。
ドキュメントではそんなことしてないんだけど。謎い。
実行するとこんな感じです。