Search code examples
dartflutterflutter-animation

Hero Animation not working inside nested Navigator


I am trying to use Hero Animations in my first flutter app, but there is already instagram like bottom navigation, that implemented using this approach, and I found that Hero Animations just doesn't work inside nested Navigators.

For example you can get Complete example from here and replace home: MainScreen(), from HeroApp class to

home: Navigator(onGenerateRoute: (_) {
  return MaterialPageRoute(builder: (_) => MainScreen());
}),

and hero animation will break.

Maybe there is some another approaches to implement bottom navigation with independent stacks for each tab, that don't use nested navigators, but I haven't found any.

So any advice much appreciated.

UPD: I just realized that answer should be in MaterialApp class and bingo!

There is naive solution that works:

home: Navigator(
  onGenerateRoute: (_) => MaterialPageRoute(builder: (_) => MainScreen()),
  observers: [HeroController()],
),

But in MaterialApp source code things are little more complicated, so maybe there are some hidden things, that broke my naive solution. Therefore question is still open.


Solution

  • This is because Hero relies on a HeroController which the navigator in MaterialApp has but your custom one does not, to fix this just add the controller, like this.

    import 'package:flutter/material.dart';
    
    class Home extends StatefulWidget {
      @override
      _HomeState createState() => _HomeState();
    }
    
    class _HomeState extends State<Home> {
      HeroController _heroController;
    
      @override
      void initState() {
        super.initState();
        _heroController = HeroController(createRectTween: _createRectTween);
      }
    
      @override
      Widget build(BuildContext context) {
        return Navigator(
          observers: [_heroController],
          onGenerateRoute: (settings) {
            return MaterialPageRoute(
                settings: settings, builder: (context) => Text(''));
          },
        );
      }
    
      RectTween _createRectTween(Rect begin, Rect end) {
        return MaterialRectArcTween(begin: begin, end: end);
      }
    }