Search code examples
flutterdartanimationnavigationflutter-animation

How to implement custom page transition with animation when navigate from one page to another?


I want to achieve below custom animation when navigation from one page to another i am trying with hero animation but no luck any help will appreciated. Thanks! Here is gif, which i want to implement


Solution

  • I'd take look at this doc https://docs.flutter.dev/cookbook/animation/page-route-animation first.

    I'd propose a mix between example shown there of slide-in transition where new page slides from the bottom in your example and mix it with fade-in transition shown here:

    import 'package:flutter/material.dart';
    import 'list.dart';
    
    import 'main.dart';
    
    class FadeAnimation extends StatelessWidget {
      static const routeName = 'Fade_Animation';
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Fade Animation"),
          ),
          body: ListView.builder(
              itemCount: curveList.length,
              itemBuilder: (context, index) {
                return Card(
                  child: ListTile(
                    title: Text("${curveList[index]}"),
                    leading: CircleAvatar(
                      child: Text("${index + 1}"),
                      backgroundColor: Colors.white,
                    ),
                    onTap: () {
                      print(curveList.length);
                      Navigator.of(context).push(PageRouteBuilder(
                          pageBuilder: (context, animation, anotherAnimation) {
                            return ReturnPage();
                          },
                          transitionDuration: Duration(milliseconds: 2000),
                          transitionsBuilder:
                              (context, animation, anotherAnimation, child) {
                            animation = CurvedAnimation(
                                curve: curveList[index], parent: animation);
                            return FadeTransition(
                              opacity:animation,
                              child: child,
                            );
                          }));
                    },
                  ),
                );
              }),
        );
      }
    }
    

    The list.dart file:

    import 'package:flutter/animation.dart';
    
    
    List<Curve> curveList = [
      Curves.bounceIn,
      Curves.bounceInOut,
      Curves.bounceOut,
      Curves.decelerate,
      Curves.ease,
      Curves.easeIn,
      Curves.easeInBack,
      Curves.easeInCirc,
      Curves.easeInCubic,
      Curves.easeInExpo,
      Curves.easeInOut,
      Curves.easeInOutBack,
      Curves.easeInOutCirc,
      Curves.easeInOutCubic,
      Curves.easeInOutExpo,
      Curves.easeInOutQuad,
      Curves.easeInOutQuart,
      Curves.easeInOutQuint,
      Curves.easeInOutSine,
      Curves.easeInQuad,
      Curves.easeInQuart,
      Curves.easeInQuint,
      Curves.easeInSine,
      Curves.easeInToLinear,
      Curves.easeOut,
      Curves.easeOutBack,
      Curves.easeOutCubic,
      Curves.easeOutExpo,
      Curves.easeOutQuad,
      Curves.easeOutQuart,
      Curves.easeOutQuint,
      Curves.easeOutSine,
      Curves.elasticIn,
      Curves.elasticInOut,
      Curves.elasticOut,
      Curves.fastLinearToSlowEaseIn,
      Curves.fastOutSlowIn,
      Curves.linear,
      Curves.linearToEaseOut,
      Curves.slowMiddle,
    ];
    

    Combination of the two should be exactly what you're looking for.

    main.dart file:

    import 'package:flutter/material.dart';
    
    import 'fadeAnimation.dart';
    
    
    main() {
      runApp(MaterialApp(
        routes: {
          FadeAnimation.routeName: (context) => FadeAnimation(),
        },
        theme: ThemeData.dark(),
        debugShowCheckedModeBanner: false,
        home: SafeArea(
          child: Scaffold(
            appBar: AppBar(title: Text("Page Tranaction")),
            body: ListView.builder(
              itemBuilder: (context, index) {
                return Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Card(
                    child: ListTile(
                      onTap: () {
                        Navigator.of(context).pushNamed(animationTypeList[index]);
                      },
                      leading: CircleAvatar(
                        backgroundColor: Colors.white,
                        child: Text("${index + 1}"),
                      ),
                      title: Text(animationTypeList[index].toString()),
                    ),
                  ),
                );
              },
              itemCount: animationTypeList.length,
            ),
          ),
        ),
      ));
    }
    
    class ReturnPage extends StatelessWidget {
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Center(
            child: Text('you're here'),
          ),
        );
      }
    }
    
    var animationTypeList = [
      FadeAnimation.routeName,
    ];
    

    Or instead of combining the 2 during transition wrap widget that contains the next screen with fade-in widget so when it gets created it fades in only once with some internal variable keeping track of that. That way you would have for example: slide-in animation during transition and widget you're transiting to would be opaque at first with gradual fade-in. Or the other way around.

    Hope this helps!