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 タップしたら詳細画面に行くってパターンが多いですよね。そのときしゅっとアニメーションしたらかっこいい…!やってみよう。
データの入れ物作ります。
public class Person { public string Id { get; set; } = Guid.NewGuid().ToString(); public string Name { get; set; } }
とりあえずお試しなので App クラスあたりにグローバルでリスト持たせておきましょう。
public static 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> public sealed partial class 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 で下準備して画面遷移します。
private void 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; protected override void 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); }
戻る方向もアニメーションをつけます。遷移先のページから戻る前にアニメーションの下準備をして…
private void 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> public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); listView.ItemsSource = App.People; } private Person _scrollTarget; protected override void OnNavigatedTo(NavigationEventArgs e) { if (e.Parameter is string id) { _scrollTarget = App.People.FirstOrDefault(x => x.Id == id); } } private void 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 を使って少し遅らせてやってます。これをしないと自分のところではアニメーションしてくれなかった…。
ドキュメントではそんなことしてないんだけど。謎い。
実行するとこんな感じです。