在窗口小部件树

时间:2018-03-19 19:47:47

标签: flutter

我从globalKey导航到Screen A并点击"取消"后,我遇到Screen B错误按钮返回Screen A

问题似乎是Screen B

  • A)未正确处理
  • B)没有做其他事情
  • 的事情

我实际上并不知道:

  • 如果我删除使用globalKey,会发生什么不好的事情? (为了更好地理解基本面)
  • 如何正确解决此问题?

StatefulWidget文档说明:enter link description here

  

StatefulWidget在从一个状态移动时保持相同的状态对象   如果其创建者使用GlobalKey,则树中的位置为另一个   它的关键。因为具有GlobalKey的窗口小部件最多可以使用一个   在树中的位置,使用GlobalKey的小部件最多只有一个   相关元素。 该框架利用了此属性   使用全局键从树中的一个位置移动窗口小部件时   通过嫁接与此相关联的(唯一)子树来实现另一个   小部件从旧位置到新位置(而不是   在新位置重新创建子树)。国家对象   与StatefulWidget相关联的是与其余的一起移植的   子树,这意味着State对象被重用(而不是   重新创建)在新的位置。 但是,为了符合条件   嫁接时,小部件必须插入到新的位置   相同的动画帧,它已从旧位置删除。

控制台错误输出:

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
Duplicate GlobalKey detected in widget tree.
The following GlobalKey was specified multiple times in the widget tree. This will lead to parts of
the widget tree being truncated unexpectedly, because the second time a key is seen, the previous
instance is moved to the new location. The key was:
- [LabeledGlobalKey<FormFieldState<String>>#3c76d]
This was determined by noticing that after the widget with the above global key was moved out of its
previous parent, that previous parent never updated during this frame, meaning that it either did
not update at all or updated before the widget was moved, in either case implying that it still
thinks that it should have a child with that global key.
The specific parent that did not update after having one or more children forcibly removed due to
GlobalKey reparenting is:
- Column(direction: vertical, mainAxisAlignment: start, crossAxisAlignment: center, renderObject:
RenderFlex#7595c relayoutBoundary=up1 NEEDS-PAINT)
A GlobalKey can only be specified on one widget at a time in the widget tree.

所以这部分错误输出:

  

以前的父级在此框架期间从未更新过,这意味着它   要么根本没有更新,要么在小部件移动之前更新

让我觉得我的旧状态窗口小部件有一些机会做某事(重新定位自己或发布一些东西以便正确处理。

framework.dart assert(_children.contains(child))上的 @override void forgetChild(Element child) { assert(_children.contains(child)); assert(!_forgottenChildren.contains(child)); _forgottenChildren.add(child); } 似乎失败了。

select * from candy_id_seq;

12 个答案:

答案 0 :(得分:8)

就我而言,它喜欢一个热重载错误。重新启动调试对我有用。

答案 1 :(得分:2)

感谢Gunter的作品,我确定这是因为屏幕没有妥善处理。

Flutter的pushReplacement拨打Route.dispose电话,最终会处理该屏幕。

我仍然不确定是否会发挥作用:

  必须将

小部件插入到同一动画中的新位置   帧

我不确定哪种情况会从这种诡计中受益。但是,我的问题解决了。我只需要打电话来弹出或替换。

以下是可用选项:

  • 使用pushA的{​​{1}}和B
  • Navigator.pop
  • 使用BpushReplacement以及AB
  • B

我最近开始使用Fluro进行路由,还有更多方法可以处理这些情况(请注意可选参数replace):

  • 使用Arouter.navigateTo(context, route, replace: false)的{​​{1}}和A的{​​{1}}
  • 使用B中的Navigator.pop B router.navigateTo(context, route, replace: true) A B(密钥为B

答案 2 :(得分:1)

解决此问题的最佳方法,对我有用:

class _HomeScreenState extends State<HomeScreen> {
   GlobalKey<FormState> _homeKey = GlobalKey<FormState>(debugLabel: '_homeScreenkey');
   @override
   Widget build(BuildContext context) {
     return Container(
       key: _homeKey,
     );
   }
}

答案 3 :(得分:1)

我也遇到了这个问题。 我有一个四个屏幕底部的选项卡式应用程序和一个“注销”方法。 但是,该注销方法正在调用pushReplacementNamed。 这样可以防止持有全局密钥(不同于注销功能)的类调用dispose。

解决方案是使用popAndPushNamed更改pushReplacementNamed以返回到我的“登录”屏幕。

答案 4 :(得分:1)

请确保您没有Form的父母,而Form的孩子也没有key

答案 5 :(得分:0)

我也有类似的错误。我的回答是,在我更新了Flutter之后,一些小部件不再具有儿童或儿童属性。就我而言,它是CircleAvatar。构建最初没有出错,但是当在应用程序中来回导航时,它将失败。

*请查看所有需要孩子的小部件,然后查看更新的文档,并确保您的参数仍然正确。

答案 6 :(得分:0)

在我的情况下,我想使用static GlobalKey<ScaffoldState> _scaffoldKey,但是当我多次使用相同的小部件时,会出现这个重复的错误。

我想给它一个唯一的字符串,并且仍然使用这个 scaffold状态。 所以我最终使用了:

static GlobalObjectKey<ScaffoldState> _scaffoldKey

initState中的

_scaffoldKey = new GlobalObjectKey<ScaffoldState>(id);

编辑: 其实我很傻我只是简单地删除了static并再次使其GlobalKey:)

答案 7 :(得分:0)

请使用SingleChildScrollview:

,如果您使用了bloc pettern,则在广播中使用strem

代码在这里:

        body: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            image: AssetImage('assets/images/abcd.jpg'),
            fit: BoxFit.cover,
          ),
        ),
        child: Container(child:Form(key: _key,
          child: Padding(
            padding: EdgeInsets.symmetric(vertical: 100.0, horizontal: 20.0),
              child: SingleChildScrollView(child:Column(
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: Image.asset('assets/images/logo.png', height: 80, width:80,),
                  ),
                  email(),
                  Padding(
                    padding: EdgeInsets.all(5.0),
                  ),
                  password(),
                  row(context),
                ],
              ),
            ),
          ),
        ),
      ),
      ),
      resizeToAvoidBottomPadding: false,
    );
  }

和集团的pettern代码在这里:

    final _email = StreamController<String>.broadcast();
    final _password = StreamController<String>.broadcast();

    Stream<String> get email => _email.stream.transform(validateEmail);
    Stream<String> get password=> _password.stream.transform(validatepassword);

    Function(String) get changeEmail=> _email.sink.add;
    Function(String) get changePassword => _password.sink.add;

    dispose(){

      _email.close();
      _password.close();
    }

}

final bloc=Bloc();

答案 8 :(得分:0)

从键变量中删除静态和最终类型,所以如果

static final GlobalKey<FormState> _abcKey = GlobalKey<FormState>();

将其更改为

GlobalKey<FormState> _abcKey = GlobalKey<FormState>();

答案 9 :(得分:0)

我不确定为什么没有人提到这一点,但就我而言,我只是将一个小部件从有状态更改为无状态。要解决此错误,您必须重新启动应用程序,而不是进行热重装。

答案 10 :(得分:0)

我有类似的问题。 在我的情况下,问题是我在处理屏幕B的方法中有一个函数,并且无法正常执行。我只是将其删除,问题已解决。

因此请确保您的dispose方法在所有屏幕上均正确执行。

答案 11 :(得分:0)

这发生在我身上,我所做的是使用我制作的扩展将整个视图包含在导航器中

Widget addNavigator() => Navigator(
    onGenerateRoute: (_) => MaterialPageRoute(
      builder: (context2) => Builder(
        builder: (context) => this,
      ),
    ),
  );
相关问题