在子树中有多个英雄共享相同的标签

277
我正在尝试使用路由从一个屏幕导航到另一个屏幕。当我点击页面上提供的路由移动按钮时,出现错误。
I/flutter ( 8790): Another exception was thrown: There are multiple heroes that share the same tag within a subtree.

这是代码:

路由:

 <String, WidgetBuilder>{
    '/first':(BuildContext context) =>NavigatorOne() ,
    '/second':(BuildContext context) =>NavigatorTwo(),
    '/third':(BuildContext context) =>NavigatorThree(),

  },

Navigator.of(context).pushNamed('/first');
Navigator.of(context).pushNamed('/second');
Navigator.of(context).pushNamed('/third');

class NavigatorOne extends StatefulWidget {
  @override
  _NavigatorOneState createState() =>  _NavigatorOneState();
}

class _NavigatorOneState extends State<NavigatorOne> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(

      appBar: AppBar(),
      body: Container(
      color: Colors.green,
      child: RaisedButton(child: Text(' one 1'),onPressed: (){
        Navigator.of(context).pushNamed('/second');
      },),
    ),
    ); 
  }
}

错误信息:

══╡ 调度器库捕获的异常 ╞═════════════════════════════════════════════════════════ I/flutter (21786): 调度回调期间抛出以下断言: I/flutter (21786): 在子树中有多个共享相同标记的 Hero。 I/flutter (21786): 对于将要进行动画处理的每个子树(通常是一个PageRoute子树),每个Hero必须具有唯一的非空标记。 I/flutter (21786): 在本例中,多个hero具有以下标记:<默认浮动操作按钮标记>

如何解决?

13个回答

706

我之前也遇到过这个问题,原因是我在一个屏幕上放置了两个 FloatingAction 按钮。为了解决这个错误,我必须为每个 FloatingActionButton 添加 heroTag 属性和值。

示例:

FloatingActionButton(
    heroTag: "btn1",
    ...
)

FloatingActionButton(
    heroTag: "btn2",
    ...
)

根据您提供的示例代码,似乎没有FloatingActionButton,但出现的错误似乎确实涉及它:

I/flutter (21786): In this case, multiple heroes had the following tag: default FloatingActionButton tag

也许您在导航到的页面上使用了它,从而触发了错误。请注意,如果您正在以编程方式创建带有标记的英雄,则需要找到一种为它们提供不同标记的方法。例如,如果您有一个 ListView.builder() 创建了 FloatingActionButtons,可以尝试使用字符串格式传递标记,使每个按钮具有不同的标记,例如:heroTag: "btn$index"


42
你可以简单地将它设为 null:heroTag: null。 - mik
21
在一个带有嵌套HeroListTile中可能会出现类似的问题。这个Hero不仅仅是一个,而是由你的items.length数量所决定的,因此标记应该是'tag$index' - mrahimygk
3
哇!我一直在导航到一个黑屏上。我知道屏幕可以正常加载,因为我放了一个自动播放的声音文件来测试。最后注意到这个“hero”错误消息并找到了你的回复 - 谢谢!确实非常有帮助。 - Donna
谢谢。我有多个FloatingActionButton,这个解决方案对我很有效。 - dwcho
不想开新问题,我的问题是如果有人能回答:在这种情况下,多个英雄具有以下标记:<SnackBar Hero tag - Column(direction: vertical, mainAxisAlignment: start, mainAxisSize: min, crossAxisAlignment: stretch)>。 - vat69
显示剩余6条评论

86

您可以设置一个唯一的 ID,或者仅将其设置为 null

FloatingActionButton(
  heroTag: null,
  ...
)

我的整个项目中都没有“FloatingActionButton”,但是当我从子屏幕导航到父屏幕时仍然会出现此错误。请建议我该怎么解决?非常感谢。 - Kamlesh
1
@Kamlesh 剩余的异常将指示需要 heroTag 的小部件。"在这种情况下,多个英雄具有以下标签:<默认浮动操作按钮标签>。 - a7md0
它像魔术一样奏效,但这会有副作用吗? - Utopion

25

仅供未来的读者参考:

感谢 @m.vincent 的评论,对于我来说造成这个错误的原因是我在 SliverChildBuilderDelegate 中使用了 Hero,而它(显然)具有索引,所以我使用了类似于 'tag$index' 的标签与索引一起使用,就像这样:

SliverChildBuilderDelegate(
    (BuildContext context, int index) {
      return Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Hero(
              tag: 'tagImage$index',
              child: Image.asset(
                'image source here',
              ),
            ),

注意:这可能会发生在任何具有创建索引子项的小部件,例如ListView.Builder


1
谢谢,这非常有帮助。当您导航到下一页时,请传递“tap index”。以匹配当前标签页的英雄标签和下一页英雄标签名称。 - Abdullah Khan
这正是我想要的解决方案,谢谢。 - Speedy11

11

8

对我来说,只是给我的 FloatingActionButtons 添加一个独特的heroTag并没有起作用。最终,我将heroTag包装在一个Text小部件中,这使问题得到解决。

new FloatingActionButton(
    heroTag: Text("btn1"),
    ...
)

new FloatingActionButton(
    heroTag: Text("btn2"),
    ...
)

2
这真的很奇怪。 - Luke Pighetti
1
我的整个项目中都没有“FloatingActionButton”,但是当我从子页面导航回父页面时,仍然会出现此错误。请给我建议,解决方法是什么?非常感谢。 - Kamlesh
1
不要这样做!英雄小部件需要一个对象,在这种情况下,它将调用小部件的toString方法。 - martinseal1987

4
这是正确的,因为根据Flutter文档,每个路由(屏幕)应该只有一个浮动操作按钮,除非你显式地设置了英雄标签。 Flutter Docs 如果没有明确设置,那么每个路由(即每个屏幕)只能有一个FloatingActionButton,否则会出现标签冲突(在一个路由上多个英雄不能有相同的标签)。Material Design规范建议每个屏幕只使用一个浮动操作按钮。

3

我遇到过同样的错误。这是因为在单个屏幕上多次使用像浮动操作按钮这样的按钮。
以前我使用了一个浮动操作按钮,但现在我已将其更改为手势检测器以使用ontap,所以它可以工作。

  GestureDetector(

              //backgroundColor: Colors.amber[100],
              onTap: add,
              child: Icon(
                FontAwesomeIcons.plus,
                size: 30,
              ),
            ),
            SizedBox(
              width: 20,
            ),
            GestureDetector(
             // heroTag: "btn2",
             // backgroundColor: Colors.amber[100],
              onTap: sub,
              child: Icon(FontAwesomeIcons.minus, size: 30),
            ),

我也遇到了这个错误,因为在一个屏幕上我使用了多个浮动操作按钮(4个浮动在视频播放器上方)。 - Harmen

2

使用英雄标签作为字符串添加任意数量的小部件

  Widget floatingButt(Function function, IconData icon, String heroTag) {
    return FloatingActionButton(
      onPressed: function,
      heroTag: heroTag,
      materialTapTargetSize: MaterialTapTargetSize.padded,
      backgroundColor: Constants.primaryColor, // from your values file
      child: Icon(
        icon,
        size: 36.0,
      ),
    );
  }

1
我的整个项目中都没有FloatingActionButton,但当我从子屏幕导航到父屏幕时仍然会出现此错误。请建议我解决方案?非常感谢。 - Kamlesh

1
我犯了一个简单的错误,试图将Scaffold传递到另一个小部件的子级中,这导致了相同的错误。

0

解决这个 heroTag 问题的简单方法是提供一个唯一值作为该属性。它可以是一个字符串值。在我的情况下,我将其提供为一个字符串转换的索引值。以下是我的解决方案,完美地工作。

FloatingActionButton(
  onPressed: (){ 
    print(index); 
    Navigator.push( context, 
       MaterialPageRoute( builder: (context)=> AddLead()
       ),
     );
    }, 
  heroTag: '$index',
  child: Image.asset('assets/pencil.png',height: 30, width: 30,), backgroundColor: Constants.myColor, 
),

欲了解更多信息,请点击此链接https://wise4rmgodadmob.medium.com/how-to-solve-there-are-multiple-heroes-that-share-the-same-tag-within-a-subtree-a5146fdec2b8


我的整个应用程序中都没有使用任何 heroTag,但在编译时仍然出现错误:“在子树中有多个共享相同标记的 hero”,请建议问题所在以及如何解决。谢谢。 - Kamlesh
你有看到我发布的评论吗?请检查并提供建议。谢谢。 - Kamlesh

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