Flutter:Widget构建上的Run方法已完成


134

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


您不太可能希望在中启动登录过程build。可以多次调用构建。
君特Zöchbauer

Answers:


195

你可以用

https://github.com/slightfoot/flutter_after_layout

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

基本上是

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

谢谢@thomas,您的回答对我非常有帮助。我在两天之前进行了这项工作,现在他们以及阅读完您的答案之后。再次感谢您,工作非常顺利
Ravindra Bhanderi

8
参见@ anmol.majhail答案:WidgetsBinding.instance.addPostFrameCallback((_) => yourFunciton(context));不再工作
Pablo Insua,

嗨,@ Thomas,它对我不起作用。仍然会得到null异常。任何想法 ?
zukijuki

1
@anunixercoder:这取决于您的用例。有时,您应使用以外的其他方式调用它initState,例如。在中build
Giraldi

2
您应该setStateyourFunction方法内调用以使其正常工作
Pars

92

更新: Flutter v1.8.4

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

加工:

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

加工

import 'package:flutter/scheduler.dart';

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

1
第二个不再有效。NoSuchMethodError (NoSuchMethodError: The method 'addPostFrameCallback' was called on null. Receiver: null
奥利弗·迪克森

1
@EliaWeiss-它取决于您的用例-这只是在构建后在Widget上调用函数的一种方式。典型的用法是init()
anmol.majhail 19/12/23

21

有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() );
}

14

Flutter 1.2-飞镖2.2

根据官方指南和消息来源,如果您想确定还绘制了布局的最后一帧,则可以编写例如:

import 'package:flutter/scheduler.dart';

void initState() {
   super.initState();
   if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
        SchedulerBinding.instance.addPostFrameCallback((_) => yourFunction(context));
   }
}

对我来说,这是行不通的,因为在initState()时,我获得了带有SchedulerPhase.idle值的schedulerPhase ...实际起作用的是在build()中添加该检查
Alessio

11

如果您正在寻找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屏幕完成渲染布局后立即调用。如果您处于调试模式,则即使在热重载时也不会再被调用,直到明确地有时间这样做为止。


从我的示例中,您可以像使用a一样使用StatefulWidget类来处理它的State对象,StatelessWidget但是我不建议这样做。我还没有发现任何问题,但是请先尝试在State对象中实现所有内容
jerinho.com

2
flutter.dev/docs/cookbook/networking/fetch-data Google建议在initState()上调用数据获取。因此,此解决方案没有问题,实际上,这应该是公认的答案。
开发人员

在React Native中,数据获取可以componentWillMount在布局渲染之前完成。Flutter提供了更简单的解决方案。initState如果我们知道如何正确进行数据提取和布局渲染,则足够了
jerinho.com

1
componentWillMount将很快被弃用。因此,将在安装和构造组件之后进行读取。
开发人员

10

在flutter版本1.14.6中,Dart版本28中。

以下是对我有用的方法,您只需要将build方法之后想要发生的一切捆绑到单独的方法或函数中即可。

@override
void initState() {
super.initState();
print('hello girl');

WidgetsBinding.instance
    .addPostFrameCallback((_) => afterLayoutWidgetBuild());

}

5

最好的方法,

1. WidgetsBinding

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

2. WidgetsBinding

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

可以在内部调用它initState,在用渲染完成Build小部件之后,两者都将仅被调用一次。

@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



0

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

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

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

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

之后也立即调用此方法initStateBuildContext.dependOnInheritedWidgetOfExactType从此方法调用是安全的。

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

这是您的回调功能

executeAfterBuildComplete([BuildContext context]){
    print("Build Process Complete");
  }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.