preface

Use navigator.of (context).push(Route Route) in Flutter; The Route object is passed by the MaterialPageRoute(Builder: () {}) method. When used, the default transition animation will be added during route jumps. When you need to animate a custom Route transition, use PageRouteBuilder. This class is provided by Flutter to create a custom Route. Instantiating this class gives you a Route object.

PageRouteBuilder

Creating a custom route transition animation using PageRouteBuilder requires passing in two callback functions as parameters, one necessary parameter pageBuilder, which is used to create the page to jump to, and the other function transitionsBuilder, This function is where the transition animation is implemented.

The child parameter of transitionsBuilder is a transitionsBuilder widget returned by the pageBuilder function. The pageBuilder method is called only when the route is first built. A Flutter automatically avoids extra work because the child keeps the same instance throughout the transition.

PageRouteBuilder(
  pageBuilder: (
      BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
    ) {
      return widget;
    },
    transitionsBuilder: (
      BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
      Widget child,
    ) {
      returnchild; });Copy the code

To create a custom route, you need to inherit PageRouteBuilder and then implement the constructor of the custom route.

/ / define
class YourRoute extends PageRouteBuilder {
  final Widget page;

  YourRoute(this.page)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return page;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) {
            returnchild; }); }/ / use
Navigator.of(context).push(YourRoute(NewPage()));
Copy the code

The sample

Use FirstPage and SecondPage to display the effect

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, home: FirstPage(), ); }}class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Page'),
        elevation: 0.0,
        backgroundColor: Colors.purple,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(
            child: RaisedButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (context) => SecondPage()),
                );
              },
              child: Text('Next Page'), ), ) ], ), backgroundColor: Colors.purple, ); }}class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Page'),
        elevation: 0.0,
        backgroundColor: Colors.deepPurpleAccent,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(
            child: RaisedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Go Back'), ), ) ], ), backgroundColor: Colors.deepPurpleAccent, ); }}Copy the code

FadeTransition

class FadeRoute extends PageRouteBuilder {
  final Widget page;

  FadeRoute(this.page)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return page;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) {
            returnFadeTransition( opacity: animation, child: child, ); }); }Copy the code

ScaleTransition

class ScaleRoute extends PageRouteBuilder {
  final Widget page;

  ScaleRoute(this.page)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return page;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) {
            return ScaleTransition(
              alignment: Alignment.bottomLeft,
              scale: Tween(
                begin: 0.0,
                end: 1.0,
              ).animate(
                CurvedAnimation(
                  parent: animation,
                  curve: Curves.easeInOut,
                ),
              ),
              child: child,
            );
          },
          transitionDuration: Duration(seconds: 1)); } Navigator.of(context).push(ScaleRoute(SecondPage()));Copy the code

RotationTransition

class RotationRoute extends PageRouteBuilder {
  final Widget page;

  RotationRoute(this.page)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return page;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) {
            Animation myAnimation = CurvedAnimation(
              parent: animation,
              curve: Curves.easeInBack,
            );

            return RotationTransition(
              turns: myAnimation,
              child: child,
            );
          },
          transitionDuration: Duration(seconds: 1)); } Navigator.of(context).push(RotationRoute(SecondPage()));Copy the code

ScaleRotationRoute

Combine two transition animations

class ScaleRotationRoute extends PageRouteBuilder {
  final Widget page;

  ScaleRotationRoute(this.page)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return page;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) {
            return ScaleTransition(
              scale: animation,
              child: RotationTransition(
                turns: Tween(
                  begin: 0.0,
                  end: 1.0,
                ).animate(
                  CurvedAnimation(parent: animation, curve: Curves.linear),
                ),
                child: child,
              ),
            );
          },
          transitionDuration: Duration(milliseconds: 800)); } Navigator.of(context).push(ScaleRotationRoute(SecondPage()));Copy the code

TransformRoute

Create 3D effects using the Transform widget

import 'dart:math' show pi;

class TransformRoute extends PageRouteBuilder {
  final Widget page;

  TransformRoute(this.page)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return page;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) {
            return Transform(
              transform: Matrix4.identity()
                // Similar to the 'perspective' property in CSS, determine the distance between the z=0 plane and the user
                ..setEntry(3.2.0.0001)
                ..rotateX(animation.value * pi * 2)
                ..rotateY(animation.value * pi * 2),
              alignment: FractionalOffset.center,
              child: child,
            );
          },
          transitionDuration: Duration(seconds: 2)); } Navigator.of(context).push(TransformRoute(SecondPage()));Copy the code

EnterExitRoute

Animate both the entry and exit pages

class EnterExitRoute extends PageRouteBuilder {
  final Widget enterPage;
  final Widget exitPage;

  EnterExitRoute(this.enterPage, this.exitPage)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return exitPage;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) =>
              Stack(
            children: [
              SlideTransition(
                position: Tween<Offset>(
                  begin: Offset(0.0.0.0),
                  end: Offset(1.0.0.0),
                ).animate(
                  CurvedAnimation(parent: animation, curve: Curves.easeIn),
                ),
                child: enterPage,
              ),
              SlideTransition(
                position: Tween<Offset>(
                  begin: Offset(1.0.0.0),
                  end: Offset.zero,
                ).animate(
                  CurvedAnimation(parent: animation, curve: Curves.easeInOut),
                ),
                child: exitPage,
              )
            ],
          ),
        );
}

Navigator.of(context).push(
  EnterExitRoute(FirstPage(), SecondPage()),
);
Copy the code

useNavigator.pushNamedMethods the jump

The name of the jump route is judged in onGenerateRoute, and the transition animation is added for the specific route.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: FirstPage(),
      onGenerateRoute: (settings) {
        switch (settings.name) {
          case '/second':
            return ScaleRoute(SecondPage());
            break;
          default:
            return null; }}); } } Navigator.pushNamed(context,'/second', arguments: {});
Copy the code

Set the global route transition animation

The default Flutter route transition animation is created by the buildTransitions method, which uses the theme.of (context).pageTransitionsTheme method. Therefore, it is possible to define a global route jump transition animation.

@override
Widget buildTransitions(context, animation, secondaryAnimation, child) {
    final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme;
    return theme.buildTransitions<T>(this, context, animation, secondaryAnimation, child);
}
Copy the code

Start with a custom TransitionBuilder, and the buildTransitions method returns the jump page. Then configure the Theme’s pageTransitionsTheme and set the corresponding platform. Finally, when jumping to the page using MaterialPageRoute or CupertinoPageRoute, there will be a custom transition animation.

class ScaleTransitionBuilder extends PageTransitionsBuilder {
  @override
  Widget buildTransitions<T>(
    route,
    context,
    animation,
    secondaryAnimation,
    child,
  ) {
    returnScaleTransition( scale: CurvedAnimation(parent: animation, curve: Curves.easeIn), child: child, ); }}class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: FirstPage(),
      theme: ThemeData(
        pageTransitionsTheme: PageTransitionsTheme(
          builders: {
            TargetPlatform.android: ScaleTransitionBuilder(),
            TargetPlatform.iOS: ScaleTransitionBuilder(),
          },
        ),
      ),
    );
  }
}

Navigator.push(context, MaterialPageRoute(builder: (ctx) => SecondPage()));
Copy the code

Encapsulate the animation as a library

Encapsulate the custom route transition animation for easy use.

enum TransitionType {
  fade,
  scale,
  rotate,
  transform,
}

class PageTransition extends PageRouteBuilder {
  PageTransition(TransitionType type, Widget page, Duration time)
      : super(
          pageBuilder: (
            context,
            animation,
            secondaryAnimation,
          ) {
            return page;
          },
          transitionsBuilder: (
            context,
            animation,
            secondaryAnimation,
            child,
          ) {
            switch (type) {
              case TransitionType.fade:
                return FadeTransition(opacity: animation, child: child);
                break;
              case TransitionType.scale:
                return ScaleTransition(
                  scale: Tween(begin: 0.0, end: 1.0).animate(
                    CurvedAnimation(parent: animation, curve: Curves.easeInOut),
                  ),
                  child: child,
                );
                break;
              case TransitionType.rotate:
                return RotationTransition(
                  turns: CurvedAnimation(
                    parent: animation,
                    curve: Curves.easeInBack,
                  ),
                  child: child,
                );
                break;
              case TransitionType.transform:
                returnTransform( transform: Matrix4.identity() .. setEntry(3.2.0.0001)
                    ..rotateX(animation.value * pi * 2)
                    ..rotateY(animation.value * pi * 2),
                  alignment: FractionalOffset.center,
                  child: child,
                );
                break;
              default:
                return child;
            };
          },
          transitionDuration: time,
        );
}

/ / use
Navigator.push(
  context,
  PageTransition(
    TransitionType.rotate,
    SecondPage(),
    Duration(milliseconds: 800),),}Copy the code

The original address

Refer to the article

Animate the page switch

Everything you need to know about Flutter page route transition

Perspective on Flutter