我希望能在小部件构建/加载完成后运行函数,但我不确定如何做到。
我的当前用例是检查用户是否已经通过身份验证,如果没有,则重定向到登录视图。我不想在之前进行检查并推送登录视图或主视图,它需要在主视图加载完成后发生。
有什么方法可以实现这一点吗?
我希望能在小部件构建/加载完成后运行函数,但我不确定如何做到。
我的当前用例是检查用户是否已经通过身份验证,如果没有,则重定向到登录视图。我不想在之前进行检查并推送登录视图或主视图,它需要在主视图加载完成后发生。
有什么方法可以实现这一点吗?
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => yourFunction(context));
}
initState
之外的其他地方调用它,例如在build
中。 - GiraldiyourFunction
方法内调用 setState
以使其正常工作。 - ParsWidgetsBinding.instance.addPostFrameCallback
是否表示不良实践? - Syed Mushaheed更新: Flutter v1.8.4
两种提到的代码现在都可以正常工作:
正常工作:
WidgetsBinding.instance
.addPostFrameCallback((_) => yourFunction(context));
工作中
import 'package:flutter/scheduler.dart';
SchedulerBinding.instance.addPostFrameCallback((_) => yourFunction(context));
NoSuchMethodError (NoSuchMethodError: 方法'addPostFrameCallback'在空上被调用。 接收器:null
- Oliver Dixoncontext.state
,而在布局后state
已被清空)。 - Luke Hutchison最佳实现方式:
1. WidgetsBinding
WidgetsBinding.instance.addPostFrameCallback((_) {
print("WidgetsBinding");
});
2. SchedulerBinding
SchedulerBinding.instance.addPostFrameCallback((_) {
print("SchedulerBinding");
});
它可以在initState
内部调用,两者仅在构建小部件完成渲染后调用一次。
@override
void initState() {
// TODO: implement initState
super.initState();
print("initState");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("WidgetsBinding");
});
SchedulerBinding.instance.addPostFrameCallback((_) {
print("SchedulerBinding");
});
}
以上两个代码将会以同样的方式工作,因为它们都使用了相似的绑定框架。
StatelessWidget
,会怎么样? - Sneha Mudhigonda有三种可能的方法:
1) WidgetsBinding.instance.addPostFrameCallback((_) => yourFunc(context));
2) Future.delayed(Duration.zero, () => yourFunc(context));
3) Timer.run(() => yourFunc(context));
就 context
而言,我需要在所有 widget 渲染完成后使用 Scaffold.of(context)
。
但我个人认为,最好的方法是这样的:
void main() async {
WidgetsFlutterBinding.ensureInitialized(); //all widgets are rendered here
await yourFunc();
runApp( MyApp() );
}
Future.delayed(Duration.zero, () => yourFunc(context));
- Constantine KurbatovWidgetsBinding
并没有起作用,反而产生了错误的结果和奇怪的行为。使用Future.delayed()
解决了我的问题! - Jonathan Rhein根据官方指南和来源,如果您想确保您布局的最后一帧也被绘制出来,可以写以下代码:
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,() {//在完成时执行某些操作}); return Scaffold() };
- Constantine Kurbatov在Flutter 1.14.6版本和Dart 28版本中。
以下是对我有效的方法,您只需要将构建方法之后想要发生的一切都捆绑到一个单独的方法或函数中即可。
@override
void initState() {
super.initState();
print('hello girl');
WidgetsBinding.instance
.addPostFrameCallback((_) => afterLayoutWidgetBuild());
}
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
会在屏幕完成渲染布局后立即调用。如果您处于调试模式下,即使进行热重载,在显式到达时刻之前也不会再次调用 State.initState
。
StatefulWidget
类来处理其State
对象,就像使用StatelessWidget
一样,但我强烈不建议这样做。虽然我还没有发现任何问题,但请先尝试在State
对象内部实现所有内容。 - stackunderflowcomponentWillMount
中完成。Flutter提供了更简单的解决方案。如果我们知道如何正确地执行它,initState
足以同时完成数据获取和布局渲染。 - stackunderflowPostFrameCallback会在屏幕完全绘制之前触发,因此Devv的答案很有帮助,需要添加延迟以允许屏幕绘制。
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Future.delayed(Duration(seconds: 3), () => yourFunction());
});
}
如果您在使用新的SDK时遇到了与旧答案不兼容的问题,您可以尝试我的解决方案。我已在v3.0.4上测试过。
WidgetsBinding.instance.endOfFrame.then(
(_) {
if (mounted) {
// do some suff
// you can get width height of specific widget based on GlobalKey
};
},
);
SchedulerBinding.instance
.addPostFrameCallback((_) => setState(() {
isDataFetched = true;
}));