How to animate routes transtion relative to the previous one in flutter

2.9k Views Asked by At

I am trying to achieve something like that coupertino page transition on routing. (briefly how to target and animate both the previous and current routes).

I checked this package page_transition, but the logic used seems off as its rebuilding the previous context widget and tries to hack an animation in the new route.

even in the documentation it seems to only be about the route on top of the navigation stack.

and you end up with something like this:

 Navigator.of(context).push(AnimatedRoute(
                      prevPage: widget, nextPage: Page2()));
class AnimatedRoute extends PageRouteBuilder {

  final Widget nextPage;
  final Widget prevPage;

  AnimatedRoute({this.prevPage, this.nextPage}) : super(
    transitionDuration: Duration(milliseconds: 700),
    pageBuilder: (
      BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
    ) {
      return nextPage;
    },
    maintainState: true,
    transitionsBuilder: (
      BuildContext context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
      Widget child,
    ) {
      return Material(
        child: Stack(
          overflow: Overflow.visible,
          children: <Widget>[
            SlideTransition(
              position: Tween<Offset>(
                begin: const Offset(0.0, 0.0),
                end: const Offset(-0.3, 0.0),
              ).animate(animation),
              child: prevPage,
            ),

            SlideTransition(
              position: Tween<Offset>(
                begin: const Offset(1.0, 0.0),
                end: Offset.zero,
              ).animate(animation),
              child: AnimatedBuilder(
                animation: animation,
                builder: (c, w) {
                  return Material(
                    shadowColor: Colors.black,
                    // elevation: 10.0 * animation.value,
                    child: nextPage
                  );
                },
              ),
            )
          ],
        ),
      );
    }
  );
}

apart from the rebuild this also doesn't take in account the state of the older widget.

a better way to handle that is appreciated

2

There are 2 best solutions below

1
On

There are other packages too like you can use getx although it is bloated with features, but still it also has a lot of transition to apply b/w both pages. You can check their source code too if you want.

Also why not you use Cupertino Transition it is great and supported by flutter?

7
On

You can use PageRouteBuilder to be able to handle transition both for the page you are transitioning from and the one you are transitioning to as I explain below:

Note: pageBuilder takes 3 parameters: context, animation and secondaryAnimation. animation is used when the page is navigated to and secondaryAnimation is used for when the page is navigated from.

Suppose that we have two pages, A and B.

For page A:

Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) {
      return AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          return AnimatedBuilder(
            animation: secondaryAnimation,
            builder: (context, innerChild) {
              retrun Transform.scale(
                scale: (animation.value - secondaryAnimation.value),
                child: A(),
              );
            },
          );
        },
      );
    },
  ),
);

And for page B:

Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) {
      return AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          return AnimatedBuilder(
            animation: secondaryAnimation,
            builder: (context, child) {
              return Transform.translate(
                offset: Offset(
                  1.0 - animation.value,
                  0.0,
                ),
                child: B(),
              );
            },
          );
        },
      );
    },
  ),
);

This will lead to a transition like the gif below:

Transition sample

(gif explanation: first page moves out with scaling down and second page comes in like a slide transition)