嵌套导航器中的英雄动画无法正常工作

22

我正在尝试在我的第一个Flutter应用中使用Hero动画,但是已经有了类似Instagram的底部导航,使用这种方法实现,我发现Hero动画无法在嵌套Navigator中正常工作。

例如,您可以从此处获取完整示例,并将HeroApp类中的home:MainScreen(),替换为

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

并且英雄动画将会出现故障。

也许有其他方法来为每个选项卡实现独立堆栈的底部导航,而不使用嵌套导航器,但我没有找到任何方法。

所以,任何建议都将不胜感激。

更新:我刚意识到答案应该在MaterialApp类中,太棒了!

有一个简单的解决方案:

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

但在MaterialApp源代码中,情况要复杂一些,所以可能有一些隐藏的东西破坏了我的天真解决方案。因此问题仍然是未解决的。


你不应该一开始就嵌套 Navigator - Rémi Rousselet
1
@RemiRousselet 嗯,但是这个答案(实际上是由Flutter团队的工程师提出的)建议使用Navigator嵌套。那么我应该如何为每个选项卡实现独立的堆栈底部导航? - Mikhail
“Navigator” 不太支持嵌套,因为它会破坏一些与导航器实例直接关联的东西,比如 Hero。那个答案相当老了;根据您的需求,可能有更好的方法来实现您的需求。 - Rémi Rousselet
@Mikhail 以上的示例是否有效? - GensaGames
1
@Mikhail,非常感谢您!!!我已经思考了很长一段时间为什么嵌套导航器中的Hero动画不起作用。我查看了许多同时运行在多个选项卡上的示例,真的所有这些示例都有自己的导航器(以跟踪其自己的堆栈),而您只需一行简单的代码就可以解决所有问题,现在动画也可以正常工作!如果可以的话我会给您1000分。谢谢! - kovalyovi
显示剩余2条评论
2个回答

33

这是因为 Hero 依赖于 HeroController,而在 MaterialApp 中的导航器有该控制器,但您自定义的导航器没有,要修复这个问题,只需添加控制器,像这样。

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);
  }
}

5
考虑重构代码以使用 HeroControllerScope 小部件。 - Chance Snow

5

2022年8月更新:

对于已接受答案的更好解决方案是将每个导航器小部件包装在一个HeroControllerScope小部件中,如图所示。

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      builder: (BuildContext context, Widget child) {
        // Builds two parallel navigators.
        return Stack(
          children: <Widget>[
            HeroControllerScope(
              controller: MaterialApp.createMaterialHeroController(),
              child: Navigator(
                onGenerateRoute: (RouteSettings settings) {
                  return MaterialPageRoute<void>(
                    settings: settings,
                    builder: (BuildContext context) {
                      return const Text('first Navigator');
                    }
                  );
                },
              ),
            ),
            HeroControllerScope(
              controller: MaterialApp.createMaterialHeroController(),
              child: Navigator(
                onGenerateRoute: (RouteSettings settings) {
                  return MaterialPageRoute<void>(
                    settings: settings,
                    builder: (BuildContext context) {
                      return const Text('second Navigator');
                    }
                  );
                },
              ),
            ),
          ],
        );
      }
    )
  );
}

这在 Navigator 2.0 上不起作用。 - SametSahin
这非常接近一个可工作的解决方案,但通常你应该将HeroController创建为小部件状态中的最终变量。 - Vik
这非常接近一个可行的解决方案,但通常你应该将HeroController创建为小部件状态中的最终变量。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接