Transiciones entre páginas con Xamarin.Forms

  • xamarin-forms

Con este post quiero enseñaos un Nuget que últimamente utilizo mucho, ya que da toque mucho más profesional a las transiciones entre páginas con Xamarin Forms. Este es SharedTransitions Principalmente me gusta porque se consigue hacer una transición mucho más suave, en la que, en lugar de pasar de una página a otra, se produce un movimiento y un escalado de vistas desde la página de origen a la de destino, y viceversa cuando la navegación es hacia atrás.

Lo único que hay que hacer, es instalar dicho paquete nuget tanto en el proyecto común como en los proyectos de cada plataforma de destino.

Hay que tener en cuenta que, para que la navegación animada funcione, es necesario utilizar SharedTransitionNavigationPage en lugar del tradiccional NavigationPage ofrecido por Xamarin.Forms

MainPage = new SharedTransitionNavigationPage(new MainPage());

Una vez hecho esto, estamos en condiciones de implementar la animación. Tanto en la Page de origen como en la de destino, hay que añadir el namespace de sharedTansitions.

xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"

El siguiente punto es asignar un identificador único a las views que queramos animar. Este identificador debe ser el mismo en la página de origen como en la página de destino. La asignación de estos identificadores se realiza mediante la propiedad sharedTransitions:Transition.Name

Con esto es suficiente para que, al navegar de una página a otra, dicha transición se haga de forma animada.

En el ejemplo que he realizado, animo 4 views desde la página de inicio hasta la página de destino.

  • 2 BoxViews. Uno redondeado que se transforma en cuadrado durante la transición, y viceversa.
  • 2 Imagenes. Una se muestra utilizando el control Image de Xamarin.Forms y otra utilizando ffImageLoading

A continuación se muestra el xaml de las páginas entre las que se realiza la navegación.

Página de origen

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"
             xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
             x:Class="SharedTransitionExample.LayoutSource"
             Title="Layout source">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="120" />
            <RowDefinition Height="120" />
            <RowDefinition Height="120" />
            <RowDefinition Height="120" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <ffimageloading:CachedImage Source="xamarinLogo.png" Grid.Row="0"
                                    sharedTransitions:Transition.Name="xamarinFfLogo"
                                    BackgroundColor="Transparent"
                                    Aspect="AspectFit"
                                    Margin="10"
                                    HeightRequest="100" WidthRequest="100"
                                    HorizontalOptions="Center" VerticalOptions="Center" />

        <Image Source="xamarinLogo.png" Grid.Row="1"
               sharedTransitions:Transition.Name="xamarinLogo"
               BackgroundColor="Transparent"
               Aspect="AspectFit"
               Margin="10"
               HeightRequest="100" WidthRequest="100"
               HorizontalOptions="Center" VerticalOptions="Center" />

        <BoxView Grid.Row="2"
                 sharedTransitions:Transition.Name="firstBoxView"
                 BackgroundColor="Red"
                 Margin="10"
                 HeightRequest="100" WidthRequest="100"
                 HorizontalOptions="Center" VerticalOptions="Center" />

        <BoxView Grid.Row="3"
                 sharedTransitions:Transition.Name="secondBoxView"
                 BackgroundColor="Blue"
                 Margin="10"
                 CornerRadius="50"
                 HeightRequest="100" WidthRequest="100"
                 HorizontalOptions="Center" VerticalOptions="Center" />

        <Button x:Name="BtnAction" Grid.Row="4"
                Text="Navigate"
                Clicked="BtnAction_Clicked"
                HorizontalOptions="Center" VerticalOptions="Center" />
    </Grid>
</ContentPage>

 

Página de destino

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"
             xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
             x:Class="SharedTransitionExample.LayoutTarget"
             Title="Layout target">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="220" />
            <RowDefinition Height="220" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <ffimageloading:CachedImage Source="xamarinLogo.png" Grid.Row="0" Grid.Column="0"
                                    sharedTransitions:Transition.Name="xamarinFfLogo"
                                    BackgroundColor="Transparent"
                                    Aspect="AspectFit"
                                    Margin="10"

                                    HorizontalOptions="Center" VerticalOptions="Center" />

        <Image Source="xamarinLogo.png" Grid.Row="1" Grid.Column="0"
               sharedTransitions:Transition.Name="xamarinLogo"
               BackgroundColor="Transparent"
               Aspect="AspectFit"
               Margin="10"
               HeightRequest="200" WidthRequest="200"
               HorizontalOptions="Center" VerticalOptions="Center" />

        <BoxView Grid.Row="0" Grid.Column="1"
                 sharedTransitions:Transition.Name="firstBoxView"
                 BackgroundColor="Red"
                 Margin="10"
                 CornerRadius="75"
                 HeightRequest="150" WidthRequest="150"
                 HorizontalOptions="Center" VerticalOptions="Center" />

        <BoxView Grid.Row="1" Grid.Column="1"
                 sharedTransitions:Transition.Name="secondBoxView"
                 BackgroundColor="Blue"
                 Margin="10"
                 HeightRequest="150" WidthRequest="150"
                 HorizontalOptions="Center" VerticalOptions="Center" />
    </Grid>
</ContentPage>

Con este ejemplo queda explicado cómo realizar transiciones entre páginas, pero ¿cómo se consigue este tipo de transiciones si se desea hacer desde un item de una colección? Para conseguirlo, entra en juego la otra propiedad de sharedTransitions, Transition.Group. Así, cada item de la colección debe tener asignado Transition.N__ame y Transition.G__roup y éste último debe ser único dentro de la lista, por lo que se recomienda asignarlo al identificador único del item.

Para hacer una pequeña ilustración de las animaciones de los items de una colección, he creado un sencillo ejemplo en el que, al hacer click en un item de la colección, se navega a una página de detalle. En esa transición desde la colección al detalle se animan 3 views, una imagen, el título y el detalle de dicho item. Se ha asociado la propiedad Transition.Name a cada uno de esos controles. MonkeyImage, MonkeyTitle y MonkeySubtitle, respectivamente. Además, se ha bindeado la propiedad Transition.Group al identificador único de cada item, es decir, a la propiedad Id. Notese que la propiedad Transition.Group no es necesario establecerla en las views de la página de destino.

Al igual que en el ejemplo anterior, ahora se muestra el xaml de las páginas entre las que se realiza la navegación.

Página de origen

<?xml version="1.0" encoding="UTF-8"?&ht;
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SharedTransitionExample.CollectionSource"
             xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"
             xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
             xmlns:fftransformations="clr-namespace:FFImageLoading.Transformations;assembly=FFImageLoading.Transformations"
             sharedTransitions:SharedTransitionNavigationPage.TransitionSelectedGroup="{Binding SelectedMonkey.Id}"
             sharedTransitions:SharedTransitionNavigationPage.BackgroundAnimation="Fade"
             sharedTransitions:SharedTransitionNavigationPage.TransitionDuration="300"
             Title="Collection source"&ht;
    <Grid&ht;
        <CollectionView x:Name="CvMonkeys"
                        SelectionMode="Single"
                        SelectedItem="{Binding SelectedMonkey}"&ht;
            <CollectionView.ItemTemplate&ht;
                <DataTemplate&ht;
                    <Grid Padding="5"&ht;
                        <Grid.RowDefinitions&ht;
                            <RowDefinition Height="*" /&ht;
                            <RowDefinition Height="*" /&ht;
                        </Grid.RowDefinitions&ht;
                        <Grid.ColumnDefinitions&ht;
                            <ColumnDefinition Width="*" /&ht;
                            <ColumnDefinition Width="4*" /&ht;
                        </Grid.ColumnDefinitions&ht;

                        <ffimageloading:CachedImage  Grid.RowSpan="2"
                                                     BackgroundColor="Transparent"
                                                     Source="{Binding ImageUrl}"
                                                     Aspect="AspectFit"
                                                     sharedTransitions:Transition.Name="MonkeyImage"
                                                     sharedTransitions:Transition.Group="{Binding Id}"
                                                     Margin="2"
                                                     VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"&ht;
                            <ffimageloading:CachedImage.Transformations&ht;
                                <fftransformations:CircleTransformation/&ht;
                            </ffimageloading:CachedImage.Transformations&ht;
                            </ffimageloading:CachedImage&ht;

                        <Label Grid.Column="1"
                               Text="{Binding Name}"
                               FontSize="Title"
                               sharedTransitions:Transition.Name="MonkeyTitle"
                               sharedTransitions:Transition.Group="{Binding Id}"
                               HorizontalOptions="Start" VerticalOptions="Center" /&ht;

                        <Label Grid.Column="1" Grid.Row="1"
                               Text="{Binding Detail}"
                               FontSize="Subtitle"
                               sharedTransitions:Transition.Name="MonkeySubtitle"
                               sharedTransitions:Transition.Group="{Binding Id}"
                               HorizontalOptions="Start" VerticalOptions="Center" /&ht;
                    </Grid&ht;
                </DataTemplate&ht;
            </CollectionView.ItemTemplate&ht;
        </CollectionView&ht;
    </Grid&ht;
</ContentPage&ht;

 

Página de destino

<?xml version="1.0" encoding="UTF-8"?&ht;
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
             xmlns:fftransformations="clr-namespace:FFImageLoading.Transformations;assembly=FFImageLoading.Transformations"
             xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"
             x:Class="SharedTransitionExample.CollectionTarget"
             Title="Collection target"&ht;
    <StackLayout&ht;
        <ffimageloading:CachedImage  BackgroundColor="Transparent"
                                     Source="{Binding Monkey.ImageUrl}"
                                     Aspect="AspectFit"
                                     sharedTransitions:Transition.Name="MonkeyImage"
                                     Margin="20"
                                     HeightRequest="200" WidthRequest="200"
                                     VerticalOptions="Start" HorizontalOptions="Center"&ht;
                            <ffimageloading:CachedImage.Transformations&ht;
                                <fftransformations:CircleTransformation/&ht;
                            </ffimageloading:CachedImage.Transformations&ht;
        </ffimageloading:CachedImage&ht;

        <Label Text="{Binding Monkey.Name}"
               FontSize="Title"
               sharedTransitions:Transition.Name="MonkeyTitle"
               HorizontalOptions="Center" VerticalOptions="Center" /&ht;

        <Label Text="{Binding Monkey.Detail}"
               FontSize="Subtitle"
               sharedTransitions:Transition.Name="MonkeySubtitle"
               HorizontalOptions="Center" VerticalOptions="Center" /&ht;
    </StackLayout&ht;
</ContentPage&ht;

 

Como es habitual, he creado un proyecto en GitHub para ofrecer más detalles de la implementación que he realizado. Espero que os sea de ayuda https://github.com/jorgediegocrespo/SharedTransition