【发布时间】:2018-09-03 03:04:03
【问题描述】:
我希望能够在小部件完成构建/加载后运行函数,但我不确定如何。 我当前的用例是检查用户是否经过身份验证,如果没有,则重定向到登录视图。我不想在之前检查并推送登录视图或主视图,它需要在主视图加载之后发生。 有什么我可以用来做这件事的吗?
【问题讨论】:
-
您不太可能希望在
build中启动登录过程。 Build 可以在任何时间多次调用。
我希望能够在小部件完成构建/加载后运行函数,但我不确定如何。 我当前的用例是检查用户是否经过身份验证,如果没有,则重定向到登录视图。我不想在之前检查并推送登录视图或主视图,它需要在主视图加载之后发生。 有什么我可以用来做这件事的吗?
【问题讨论】:
build 中启动登录过程。 Build 可以在任何时间多次调用。
你可以使用
https://github.com/slightfoot/flutter_after_layout
在布局完成后仅执行一次功能。 或者只是查看它的实现并将其添加到您的代码中:-)
基本上是这样的
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => yourFunction(context));
}
【讨论】:
WidgetsBinding.instance.addPostFrameCallback((_) => yourFunciton(context)); 不再工作
initState,例如。在build.
yourFunction 方法中调用setState 以使其正常工作
WidgetsBinding.instance.addPostFrameCallback 表明代码中有不好的做法?
更新: 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
有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() );
}
【讨论】:
Future.delayed(Duration.zero, () => yourFunc(context));
WidgetsBinding 不起作用,但会产生错误的结果和奇怪的行为。使用Future.delayed() 解决了我的问题!
最好的方法,
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
【讨论】:
根据官方指南和sources,如果您想确定布局的最后一帧也已绘制,您可以这样写:
import 'package:flutter/scheduler.dart';
void initState() {
super.initState();
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback((_) => yourFunction(context));
}
}
【讨论】:
Widget build(BuildContext context) { Future.delayed(Duration.zero,() {//some action on complete}); return Scaffold() };
如果你正在寻找 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 对象中实现所有内容
componentWillMount 中进行。 Flutter 提供了更简单的解决方案。如果我们知道如何正确操作,initState 足以用于数据获取和呈现的布局
在 Flutter 1.14.6 版、Dart 28 版中。
下面是对我有用的方法,您只需要将构建方法之后想要发生的所有事情捆绑到单独的方法或函数中。
@override
void initState() {
super.initState();
print('hello girl');
WidgetsBinding.instance
.addPostFrameCallback((_) => afterLayoutWidgetBuild());
}
【讨论】:
试试 SchedulerBinding,
SchedulerBinding.instance
.addPostFrameCallback((_) => setState(() {
isDataFetched = true;
}));
【讨论】:
如果您只想执行一次,请执行此操作,因为框架将为它创建的每个 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");
}
【讨论】:
另一个对我来说效果很好的解决方案是用Future.delayed() 包装你想要调用的函数,如下所示:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Future.delayed(Duration(seconds: 3), () => yourFunction());
});
}
【讨论】: