4. Advanced shared transitions between collection of views and their details page - GiampaoloGabba/Xamarin.Plugin.SharedTransitions GitHub Wiki

This type of shared transition is useful to animate a selected item from a collection of views (for example a listview or any custom control with bindable views) to his "details" page. To make this work we need to set the sharedTransitions:Transition.Group property. It can be a number or a string and MUST to be unique for every List Item.

Listview sample:

Bind the Transition.Group to a unique value in the source page . The Transition.Name property is used as usual to identify the views to transition.

<ListView Footer="" ItemsSource="{Binding Dogs}" HasUnevenRows="True" SelectionMode="None">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout Orientation="Horizontal">
                    <Image Source="{Binding Image}" WidthRequest="100" Margin="0,8"
                            sharedTransitions:Transition.Name="DogImage"
                            sharedTransitions:Transition.Group="{Binding Id}"/>
                    <Label Text="{Binding Title}" VerticalOptions="Center" />
                </StackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Then in the destination page, tag the views to transition. We dont have to specify the Transition Group in the destination page, the match between pages will occour with the Transition.Name property.

<StackLayout Spacing="20" Padding="10">
    <Image Source="{Binding SelectedDog.Image}" sharedTransitions:Transition.Name="DogImage"  />
    <Label Text="{Binding SelectedDog.Title}" HorizontalOptions="Center" FontAttributes="Bold" FontSize="Large" />
    <Label Text="{Binding SelectedDog.Description}" />
</StackLayout>

When navigating from the source listview page to the destination, you need to inform the NavigationPage of what Transition Group has been selected:

private async void MyItemTapped(object sender,  ItemTapEventArgs e)
{
   var tappedItemData = e.Item as MyModel;
  //this is required in order to pass the views to animate
   SharedTransitionNavigationPage.SetSelectedTransitionGroup(this, tappedItemData.Id);
   await Navigation.PushAsync(new Page3(tappedItemData));
}

Listview MVVM sample:

if you are using MVVM, you can bind the SelectedTransitionGroup property directly in XAML with binding:

<ContentPage 
    .....
    SharedTransitionNavigationPage.SelectedGroup={Binding Selectedgroup}

Then, in your VM valorize the SelectedGroup property before the push. Here a full example using the EventToCommandBehaviour from Prism (you can use whaterver you want to handle the tap in your viewmodel):

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True" Padding="0"
             xmlns:behaviors="http://prismlibrary.com"
             x:Class="TransitionApp.Views.DynamicSampleFrom" Title="Listview sample"
             sharedTransitions:SharedTransitionNavigationPage.TransitionSelectedGroup="{Binding SelectedDogId }" >

        <ListView Footer="" ItemsSource="{Binding Dogs}" HasUnevenRows="True" SelectionMode="None">
            <ListView.Behaviors>
                <behaviors:EventToCommandBehavior EventName="ItemTapped"
                                                  Command="{Binding NavigateDogCommand}" 
                                                  EventArgsParameterPath="Item" />
            </ListView.Behaviors>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <Image Source="{Binding Image}" WidthRequest="100" Margin="0,8"
                                   sharedTransitions:Transition.Name="DogImage"
                                   sharedTransitions:Transition.Group="{Binding Id}"/>
                            <Label Text="{Binding Title}" VerticalOptions="Center" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
</ContentPage>

The ViewModel:

public class DynamicSampleFromViewModel : ViewModelBase
   {
       private List<DogModel> _dogs;
       public List<DogModel> Dogs
       {
           get { return _dogs; }
           set { SetProperty(ref _dogs, value); }
       }

       private int _selectedDogId;
       public int SelectedDogId
       {
           get { return _selectedDogId; }
           set { SetProperty(ref _selectedDogId, value); }
       }

       public DelegateCommand<DogModel> NavigateDogCommand { get; set; }

       public DynamicSampleFromViewModel(INavigationService navigationService) : base(navigationService)
       {
           NavigateDogCommand = new DelegateCommand<DogModel>(async (selectedDog) =>
           {
              SelectedDogId = selectedDog.Id;
              
              var navParam = new NavigationParameters {{nameof(selectedDog), selectedDog}}; 
              await navigationService.NavigateAsync($"{nameof(DynamicSampleTo)}",navParam);
           });
       }

       public override void OnNavigatedTo(INavigationParameters parameters)
       {
           base.OnNavigatedTo(parameters);

           if (parameters.GetNavigationMode() != NavigationMode.Back)
           {
               var description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
               Dogs = new List<DogModel>
               {
                   new DogModel {Id =1, Title = "Christmas Dog",    Image = "christmas_dog.jpg", Description = description},
                   new DogModel {Id =2, Title = "Cute Dog",         Image = "cute_dog.jpg",      Description = description},
                   new DogModel {Id =3, Title = "Lazy Dog",         Image = "lazy_dog.jpg",      Description = description},
                   new DogModel {Id =4, Title = "What the Dog??!?", Image = "what_the_dog.jpg",  Description = description},
               };
           }

       }
   }

Destination page

In the destination page, you have to just set the Transition Name property to display the animation:

<StackLayout Spacing="20" Padding="10">
    <Image Source="{Binding SelectedDog.Image}" sharedTransitions:Transition.Name="DogImage"  />
    <Label Text="{Binding SelectedDog.Title}" HorizontalOptions="Center" FontAttributes="Bold" FontSize="Large" />
    <Label Text="{Binding SelectedDog.Description}" />
</StackLayout>

Everything is in the sample apps, go take a look at it :)

⚠️ **GitHub.com Fallback** ⚠️