Saltar al contenido principal

Animar una transición de ruta de página

Cómo animar de una página a otra.

Un lenguaje de diseño, como Material, define comportamientos estándar al realizar transiciones entre rutas (o pantallas). A veces, sin embargo, una transición personalizada entre pantallas puede hacer que una aplicación sea más única. Para ayudar, PageRouteBuilder proporciona un objeto Animation. Esta Animation se puede usar con objetos Tween y Curve para personalizar la animación de transición. Esta receta muestra cómo realizar la transición entre rutas animando la nueva ruta a la vista desde la parte inferior de la pantalla.

Para crear una transición de ruta de página personalizada, esta receta utiliza los siguientes pasos:

  1. Configurar un PageRouteBuilder
  2. Crear un Tween
  3. Añadir un AnimatedWidget
  4. Usar un CurveTween
  5. Combinar los dos Tweens

1. Configurar un PageRouteBuilder

#

Para empezar, usa un PageRouteBuilder para crear una Route. PageRouteBuilder tiene dos retrollamadas (callbacks), una para construir el contenido de la ruta (pageBuilder), y otra para construir la transición de la ruta (transitionsBuilder).

El siguiente ejemplo crea dos rutas: una ruta de inicio con un botón "Go!", y una segunda ruta titulada "Page 2".

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: Page1()));
}

class Page1 extends StatelessWidget {
  const Page1({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.of(context).push(_createRoute());
          },
          child: const Text('Go!'),
        ),
      ),
    );
  }
}

Route<void> _createRoute() {
  return PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => const Page2(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      return child;
    },
  );
}

class Page2 extends StatelessWidget {
  const Page2({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: const Center(child: Text('Page 2')),
    );
  }
}

2. Crear un Tween

#

Para hacer que la nueva página se anime desde la parte inferior, debe animarse de Offset(0, 1) a Offset(0, 0) (normalmente definido usando el constructor Offset.zero). En este caso, Offset es un vector 2D para el Widget FractionalTranslation. Establecer el argumento dy a 1 representa una traducción vertical de una altura completa de la página.

La retrollamada (callback) transitionsBuilder tiene un parámetro animation. Es un Animation<double> que produce valores entre 0 y 1. Convierte el Animation<double> en un Animation<Offset> usando un Tween:

dart
transitionsBuilder: (context, animation, secondaryAnimation, child) {
  const begin = Offset(0.0, 1.0);
  const end = Offset.zero;
  final tween = Tween(begin: begin, end: end);
  final offsetAnimation = animation.drive(tween);
  return child;
},

3. Usar un AnimatedWidget

#

Flutter tiene un conjunto de Widgets que extienden de AnimatedWidget que se reconstruyen a sí mismos cuando cambia el valor de la animación. Por ejemplo, SlideTransition toma un Animation<Offset> y traslada a su hijo (usando un Widget FractionalTranslation) cada vez que el valor de la animación cambia.

Devolver un SlideTransition con el Animation<Offset> y el Widget hijo:

dart
transitionsBuilder: (context, animation, secondaryAnimation, child) {
  const begin = Offset(0.0, 1.0);
  const end = Offset.zero;
  final tween = Tween(begin: begin, end: end);
  final offsetAnimation = animation.drive(tween);

  return SlideTransition(position: offsetAnimation, child: child);
},

4. Usar un CurveTween

#

Flutter proporciona una selección de curvas de atenuación (easing curves) que ajustan el ritmo de la animación a lo largo del tiempo. La clase Curves proporciona un conjunto predefinido de curvas de uso común. Por ejemplo, Curves.easeOut hace que la animación comience rápido y termine lentamente.

Para usar una Curve, crea un nuevo CurveTween y pásale una Curve:

dart
var curve = Curves.ease;
var curveTween = CurveTween(curve: curve);

Este nuevo Tween todavía produce valores de 0 a 1. En el siguiente paso, se combinará con el Tween<Offset> del paso 2.

5. Combinar los dos Tweens

#

Para combinar los tweens, usa chain():

dart
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.ease;

var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));

Luego usa este tween pasándolo a animation.drive(). Esto crea un nuevo Animation<Offset> que se puede dar al Widget SlideTransition:

dart
return SlideTransition(position: animation.drive(tween), child: child);

Este nuevo Tween (o Animatable) produce valores de Offset evaluando primero el CurveTween, luego evaluando el Tween<Offset>. Cuando se ejecuta la animación, los valores se calculan en este orden:

  1. La animación (proporcionada a la retrollamada transitionsBuilder) produce valores de 0 a 1.
  2. El CurveTween mapea esos valores a nuevos valores entre 0 y 1 basados en su curva.
  3. El Tween<Offset> mapea los valores double a valores Offset.

Otra forma de crear un Animation<Offset> con una curva de atenuación es usar un CurvedAnimation:

dart
transitionsBuilder: (context, animation, secondaryAnimation, child) {
  const begin = Offset(0.0, 1.0);
  const end = Offset.zero;
  const curve = Curves.ease;

  final tween = Tween(begin: begin, end: end);
  final curvedAnimation = CurvedAnimation(parent: animation, curve: curve);

  return SlideTransition(
    position: tween.animate(curvedAnimation),
    child: child,
  );
}

Ejemplo interactivo

#