【问题标题】:Flutter: Run method on Widget build completeFlutter:小部件构建上的运行方法完成
【发布时间】:2018-09-03 03:04:03
【问题描述】:

我希望能够在小部件完成构建/加载后运行函数,但我不确定如何。 我当前的用例是检查用户是否经过身份验证,如果没有,则重定向到登录视图。我不想在之前检查并推送登录视图或主视图,它需要在主视图加载之后发生。 有什么我可以用来做这件事的吗?

【问题讨论】:

标签: dart flutter


【解决方案1】:

你可以使用

https://github.com/slightfoot/flutter_after_layout

在布局完成后仅执行一次功能。 或者只是查看它的实现并将其添加到您的代码中:-)

基本上是这样的

  void initState() {
    super.initState();
    WidgetsBinding.instance
        .addPostFrameCallback((_) => yourFunction(context));
  }

【讨论】:

  • 谢谢@thomas,你的回答对我很有帮助。我在两天前就在这方面工作,现在他们在读了你的回答之后。再次感谢你做得很好
  • 查看@anmol.majhail 答案:WidgetsBinding.instance.addPostFrameCallback((_) => yourFunciton(context)); 不再工作
  • @anunixercoder :这取决于您的用例。有时,您应该调用它而不是initState,例如。在build.
  • 您应该在yourFunction 方法中调用setState 以使其正常工作
  • 是否经常使用WidgetsBinding.instance.addPostFrameCallback 表明代码中有不好的做法?
【解决方案2】:

更新: Flutter v1.8.4

上面提到的两个代码现在都可以工作了:

工作:

WidgetsBinding.instance
        .addPostFrameCallback((_) => yourFunction(context));

工作

import 'package:flutter/scheduler.dart';

SchedulerBinding.instance.addPostFrameCallback((_) => yourFunction(context));

【讨论】:

  • 第二个不再有效。 NoSuchMethodError (NoSuchMethodError: The method 'addPostFrameCallback' was called on null. Receiver: null
  • @EliaWeiss - 这取决于您的用例 - 这只是构建后在小部件上调用函数的一种方式。典型用法将在 init()
【解决方案3】:

有3种可能的方式:

1) WidgetsBinding.instance.addPostFrameCallback((_) => yourFunc(context));

2) Future.delayed(Duration.zero, () => yourFunc(context));

3) Timer.run(() => yourFunc(context));

至于context,在我的所有小部件都被渲染后,我需要它在Scaffold.of(context) 中使用。

但以我的拙见,最好的方法是:

void main() async {
  WidgetsFlutterBinding.ensureInitialized(); //all widgets are rendered here
  await yourFunc();
  runApp( MyApp() );
}

【讨论】:

  • 在 Flutter 的 GetX 框架中,首选第二种方式(在小部件声明中):Future.delayed(Duration.zero, () => yourFunc(context));
  • 我可以确认@ConstantineKurbatov。使用 GetX 和 WidgetsBinding 不起作用,但会产生错误的结果和奇怪的行为。使用Future.delayed() 解决了我的问题!
【解决方案4】:

最好的方法,

1.小部件绑定

WidgetsBinding.instance.addPostFrameCallback((_) {
      print("WidgetsBinding");
    });

2。调度器绑定

SchedulerBinding.instance.addPostFrameCallback((_) {
  print("SchedulerBinding");
});

可以在initState内部调用,两者都只会在Build widgets渲染完成后调用一次。

@override
  void initState() {
    // TODO: implement initState
    super.initState();
    print("initState");
    WidgetsBinding.instance.addPostFrameCallback((_) {
      print("WidgetsBinding");
    });
    SchedulerBinding.instance.addPostFrameCallback((_) {
      print("SchedulerBinding");
    });
  }

上述两个代码的工作方式相同,因为它们都使用相似的绑定框架。 不同之处请参见以下链接。

https://medium.com/flutterworld/flutter-schedulerbinding-vs-widgetsbinding-149c71cb607f

【讨论】:

    【解决方案5】:

    颤振 1.2 - 飞镖 2.2

    根据官方指南和sources,如果您想确定布局的最后一帧也已绘制,您可以这样写:

    import 'package:flutter/scheduler.dart';
    
    void initState() {
       super.initState();
       if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
            SchedulerBinding.instance.addPostFrameCallback((_) => yourFunction(context));
       }
    }
    

    【讨论】:

    • 对我来说这行不通,因为在 initState() 时间我得到了具有 SchedulerPhase.idle 值的 schedulerPhase ...它实际工作的是在其中添加该检查构建()
    • 尝试以下方式:Widget build(BuildContext context) { Future.delayed(Duration.zero,() {//some action on complete}); return Scaffold() };
    【解决方案6】:

    如果你正在寻找 ReactNative 的 componentDidMount 等价物,Flutter 有它。它不是那么简单,但它的工作方式相同。在 Flutter 中,Widgets 不直接处理他们的事件。相反,他们使用 State 对象来做到这一点。

    class MyWidget extends StatefulWidget{
    
      @override
      State<StatefulWidget> createState() => MyState(this);
    
      Widget build(BuildContext context){...} //build layout here
    
      void onLoad(BuildContext context){...} //callback when layout build done
    }
    
    class MyState extends State<MyWidget>{
    
      MyWidget widget;
    
      MyState(this.widget);
    
      @override
      Widget build(BuildContext context) => widget.build(context);
    
      @override
      void initState() => widget.onLoad(context);
    }
    

    State.initState 在屏幕完成布局渲染后立即被调用。如果您处于调试模式,即使在热重载时也永远不会再次被调用,直到明确达到这样做的时间。

    【讨论】:

    • 在我的示例中,您可以使用StatefulWidget 类来处理它的State 对象,就像StatelessWidget 一样,但我强烈不推荐它。我还没有发现任何问题,但请先尝试在 State 对象中实现所有内容
    • flutter.dev/docs/cookbook/networking/fetch-data Google 建议在 initState() 上调用数据获取。因此,此解决方案没有问题,实际上这应该是公认的答案。
    • 在 React Native 中,数据获取可以在布局渲染之前在 componentWillMount 中进行。 Flutter 提供了更简单的解决方案。如果我们知道如何正确操作,initState 足以用于数据获取和呈现的布局
    • componentWillMount 将很快被弃用。因此,将在安装和构建组件后完成获取。
    【解决方案7】:

    在 Flutter 1.14.6 版、Dart 28 版中。

    下面是对我有用的方法,您只需要将构建方法之后想要发生的所有事情捆绑到单独的方法或函数中。

    @override
    void initState() {
    super.initState();
    print('hello girl');
    
    WidgetsBinding.instance
        .addPostFrameCallback((_) => afterLayoutWidgetBuild());
    
    }
    

    【讨论】:

      【解决方案8】:

      试试 SchedulerBinding,

       SchedulerBinding.instance
                      .addPostFrameCallback((_) => setState(() {
                    isDataFetched = true;
                  }));
      

      【讨论】:

        【解决方案9】:

        如果您只想执行一次,请执行此操作,因为框架将为它创建的每个 State 对象调用一次 initState() 方法。

         @override
          void initState() {
            super.initState();
            WidgetsBinding.instance
                .addPostFrameCallback((_) => executeAfterBuildComplete(context));
          }
        

        如果您想一次又一次地执行此操作,例如返回或导航到下一个屏幕等...,请执行此操作,因为 didChangeDependencies() 在此 State 对象的依赖项发生更改时调用。

        例如,如果先前对 build 的调用引用了后来更改的 InheritedWidget,则框架将调用此方法以通知此对象有关更改。

        initState 之后也立即调用此方法。从这个方法调用BuildContext.dependOnInheritedWidgetOfExactType是安全的。

         @override
          void didChangeDependencies() {
            super.didChangeDependencies();
            WidgetsBinding.instance
                .addPostFrameCallback((_) => executeAfterBuildComplete(context));
          }
        

        这是你的回调函数

        executeAfterBuildComplete([BuildContext context]){
            print("Build Process Complete");
          }
        

        【讨论】:

          【解决方案10】:

          另一个对我来说效果很好的解决方案是用Future.delayed() 包装你想要调用的函数,如下所示:

            @override
            void initState() {
              super.initState();
              WidgetsBinding.instance.addPostFrameCallback((_) {
                 Future.delayed(Duration(seconds: 3), () => yourFunction());
              });
            }
          

          【讨论】:

          • 为什么要在构建小部件后添加延迟?
          猜你喜欢
          • 2021-05-09
          • 2020-12-30
          • 2020-09-01
          • 2019-08-24
          • 2018-11-01
          • 1970-01-01
          • 2017-10-19
          • 2021-07-04
          • 1970-01-01
          相关资源
          最近更新 更多