InheritedWidget更新导致问题

时间:2018-03-22 17:34:50

标签: flutter

我使用应用顶部的继承小部件在设置新位置时更新我的​​应用程序。这样可以在我的应用中的每个可能位置刷新我的位置坐标。

但是我也有一个文本字段。几秒钟后我点击文本字段 键盘将被继承的小部件更新隐藏。 有没有办法防止颤动隐藏键盘或重新初始化状态,以便继承的小部件的更新与我的搜索字段一起工作? 当我输入一些文本时,也可能触发继承的小部件进行新的更新,但搜索栏和键盘应该保持打开状态。

 new TextField(
          controller: _controller,
          autocorrect: false,
          autofocus: true
          ...
)

1 个答案:

答案 0 :(得分:2)

Without seeing all of your code, it's a little bit difficult to know what's going on.

My best guess though is that you're using a context somewhere above the TextField to register for updates from the inherited widget.

What I'd advise you to do though is go up the widget tree from your TextField and make sure that you're not using the inherited widget in a context anywhere above it. It might be worth putting some debug statements at the beginning of your build methods to determine exactly where the build is being triggered from (the inherited widget shouldn't trigger a rebuild immediately below it if you're using it right, but stranger things have happened).

This includes if you have something like this:

MyWidget extends StatelessWidget {
  Widget build(BuildContext context) {
    Location location = MyInheritedWidget.of(context).location;
    return new Row(
      children: [
        new LocationDisplayer(location),
        new TextField( ..... ),
      ],
    );
  }    
}

The reason I say this is that from my understanding of how inherited widgets work; when it changes, whichever widgets whose contexts were used to get the inherited widget get rebuilt.

That means that even though your textfield technically isn't changing any properties, it might actually be a new textfield depending on how the build went (there's a bit of flutter magic I don't fully understand around how they decide when to make new vs re-build things) and therefore it hasn't requested focus.

Rather than having to write a bunch of new widgets to enclose whatever is using MyInheritedWidget, I believe you could use something like this:

MyWidget extends StatelessWidget {
  Widget build(BuildContext context) {
    return new Row(
      children: [
        new Builder(
          builder: (context) {
            Location location = MyInheritedWidget.of(context).location;
            return new LocationDisplayer(location);
          },
        ),
        new TextField( ..... ),
      ],
    );
  }    
}

If you're 100% sure you're not doing this anywhere, then you could go for the non-flutter way of doing things... your location class could expose a subscribe and unsubscribe method. All of the widgets where you're actually using the location call subscribe (which should also be stateful widgets) with a callback in their initState() and unsubscribe in their dispose(). The location class would simply call each of the callbacks instead of changing state as you're doing now, and within each of the callbacks you should call setState for the widget that actually shows the location.