Force Flutter重绘所有小部件

时间:2017-05-04 09:07:03

标签: dart flutter

有没有办法强制Flutter重绘所有小部件(例如在区域设置更改后)?

11 个答案:

答案 0 :(得分:15)

这种类型的用例,你有孩子可以阅读的数据,但你不想将数据显式传递给你所有孩子的构造函数参数,通常需要InheritedWidget。 Flutter将自动跟踪哪些小部件依赖于数据并重建已更改的树的部分。有LocaleQuery窗口小部件用于处理区域设置更改,您可以在Stocks example app中看到它的使用方式。

简而言之,这就是Stocks正在做的事情:

  • 对根小部件(在本例中为StocksApp)进行回调以处理区域设置更改。此回调执行一些操作,然后返回LocaleQueryData
  • 的自定义实例
  • 将此回调注册为onLocaleChanged构造函数
  • MaterialApp参数
  • 需要区域设置信息的子窗口小部件使用LocaleQuery.of(context)
  • 当语言环境发生变化时,Flutter仅重绘具有依赖于语言环境数据的小部件。

如果要跟踪区域设置更改以外的其他内容,可以创建自己的扩展InheritedWidget的类,并将其包含在应用根目录附近的层次结构中。其父级应为StatefulWidget,其密钥设置为GlobalKey,可供儿童访问。 State的{​​{1}}应该拥有您要分发的数据,并公开更改调用StatefulWidget的方法。如果子窗口小部件想要更改setState的数据,他们可以使用全局键来获取指向StateState)的指针并在其上调用方法。如果他们想要读取数据,他们可以调用key.currentState子类的静态of(context)方法,这将告诉Flutter这些小部件需要在InheritedWidget调用{{1}时重建}}

答案 1 :(得分:10)

刷新整个小部件树可能会很昂贵,并且当您在用户面前看到它时,看起来似乎并不甜美。

为此,颤振具有ValueListenableBuilder<T> class。它仅允许您重建一些您所需的小部件,而跳过昂贵的小部件。

您可以在此处查看文档ValueListenableBuilder flutter docs
或下面的示例代码:

  return Scaffold(
  appBar: AppBar(
    title: Text(widget.title)
  ),
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text('You have pushed the button this many times:'),
        ValueListenableBuilder(
          builder: (BuildContext context, int value, Widget child) {
            // This builder will only get called when the _counter
            // is updated.
            return Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Text('$value'),
                child,
              ],
            );
          },
          valueListenable: _counter,
          // The child parameter is most helpful if the child is
          // expensive to build and does not depend on the value from
          // the notifier.
          child: goodJob,
        )
      ],
    ),
  ),
  floatingActionButton: FloatingActionButton(
    child: Icon(Icons.plus_one),
    onPressed: () => _counter.value += 1,
  ),
);

而且永远不要忘记 setState(() {});

的强大功能

答案 2 :(得分:5)

简单使用:

Navigator.popAndPushNamed(context,'/screenname');

每当您需要刷新时:)

答案 3 :(得分:4)

您的Widget应该有一个setState()方法,每次调用此方法时,都会重绘窗口小部件。

  

Documentation : Widget setState()

答案 4 :(得分:3)

在这篇文章中,我将解释如何创建自定义的“ AppBuilder”小部件。

https://hillelcoren.com/2018/08/15/flutter-how-to-rebuild-the-entire-app-to-change-the-theme-or-locale/

您可以通过将其与MaterialApp一起包装来使用该小部件,例如:

Widget build(BuildContext context) {
  return AppBuilder(builder: (context) {
    return MaterialApp(
      ...
    );
  });
}

您可以使用以下方法告诉应用重建:

AppBuilder.of(context).rebuild();

答案 5 :(得分:2)

老问题,但这是解决方案:

在您的build方法中,调用rebuildAllChildren函数并将其传递给context

@override
Widget build(BuildContext context) { 
  rebuildAllChildren(context);
  return ...
}

void rebuildAllChildren(BuildContext context) {
  void rebuild(Element el) {
    el.markNeedsBuild();
    el.visitChildren(rebuild);
  }
  (context as Element).visitChildren(rebuild);
}

这将拜访所有孩子并将他们标记为需要重建。 如果将此代码放在窗口小部件树中最顶层的窗口小部件中,它将重建所有内容。

还请注意,您必须订购该特定小部件才能进行重建。另外,您可以使用一些布尔值,以便仅在您真正需要它时才重建该小部件的所有子部件(当然,这是一项昂贵的操作)。

重要提示::这是一个hack,只有在知道自己在做什么并且有充分理由这样做时,才应该这样做。我的国际化软件包中有一个示例,其中有此必要:https://pub.dev/packages/i18n_extension。正如科林·杰克逊(Collin Jackson)在回答中解释的那样,您实际上一般不应该这样做。

答案 6 :(得分:1)

对您的用例可能有用的是使用Navigator重新加载页面。我在&#34;真实&#34;之间切换时这样做和&#34;演示&#34;在我的应用程序模式。这是一个例子:

Navigator.of(context).push(
    new MaterialPageRoute(
        builder: (BuildContext context){
          return new SplashPage();
        }
    )
);

您可以替换&#34;新的SplashPage()&#34;在上面的代码中,您想要重新加载任何主要小部件(或屏幕)。可以从有权访问BuildContext的任何地方调用此代码(这是UI中的大多数位置)。

答案 7 :(得分:1)

还有一个名为states_rebuilder的发布包可以解决这个问题。

答案 8 :(得分:0)

如果要创建多语言应用程序,建议您使用本地化库来处理。甚至使用其他应用程序使用的约定。

flutter_i18n-它还具有一种在运行时重新生成的方法-记录在底部

await FlutterI18n.refresh(buildContext, languageCode, {countryCode});

它的作用是生成状态的小部件,这些状态由处理动态数据和可见性的组合singelton资源管理。

答案 9 :(得分:-1)

使用 AppBuilder 小部件制作重绘小部件

<div class="container">
  <a href="" style="border: solid">Item</a>
  <a href="" style="border: solid">Item</a>
  <a href="" style="border: solid">Item</a>
  <a href="" style="border: solid">Item</a>
</div>

答案 10 :(得分:-1)

简单使用:

Navigator.popAndPushNamed(context,'/xxx');