Flutter: 在 Widget 构建完成后运行方法

334

我希望能在小部件构建/加载完成后运行函数,但我不确定如何做到。

我的当前用例是检查用户是否已经通过身份验证,如果没有,则重定向到登录视图。我不想在之前进行检查并推送登录视图或主视图,它需要在主视图加载完成后发生。

有什么方法可以实现这一点吗?


2
你不太可能想在“build”中开始登录过程。Build可以在任何时候被多次调用。 - Günter Zöchbauer
看这个:https://dev59.com/Y6nka4cB1Zd3GeqPVuqP - shadowsheep
在我的情况下,我希望启动画面保持显示,直到我决定用户是否已登录,这样我才能将他们带过登录界面。这一点证明非常困难,因为很难确定登录界面之后的下一个界面是否已经渲染完成!... - Karolina Hagegård
15个回答

4
如果您不想使用 WidgetsBinding 或者 SchedulerBinding
  • Use Future or Timer (easy-peasy)

    Future<void> _runsAfterBuild() async {
      // This code runs after build ...
    }
    
    @override
    Widget build(BuildContext context) {
      Future(_runsAfterBuild); // <-- Use Future or Timer
      return Container();
    }
    
  • Await a dummy Future

    Future<void> _runsAfterBuild() async {
      await Future((){}); // <-- Dummy await
    
      // This code runs after build ...
    }
    
    @override
    Widget build(BuildContext context) {
      _runsAfterBuild();
      return Container();
    }
    

这行代码的意思是什么,或者它是如何工作的? await Future((){}); // <-- Dummy await - mazen amr
它之所以有效,是因为到目前为止,异步代码总是在同步代码之后被调度运行,所以 build()(同步方法)将在 _runsAfterBuild()(异步方法)开始运行之前完整地运行。 - undefined

1

使用SchedulerBinding而不是WidgetsBinding,GetX就能正常工作了

SchedulerBinding.instance.addPostFrameCallback((_) {
  // your code here
});

1

我英文不好,请谅解。

以下是需要翻译的内容:

import 'package:flutter/material.dart';

class TestBox extends StatefulWidget {
  final Color color;
  final Duration delay;

  const TestBox({
    Key? key,
    this.color = Colors.red,
    this.delay = const Duration(seconds: 5),
  }) : super(key: key);

  @override
  _TestBoxState createState() => _TestBoxState();
}

class _TestBoxState extends State<TestBox> {
  String? label;

  @override
  void initState() {
    initialMembers();
    super.initState();
  }

  void initialMembers() async {
    label = await fetchLabel();

    if (mounted) setState(() {});

    /// don't worry
    /// if `(!mounted)`, means wen `build` calld
    /// the label already has the newest value
  }

  Future<String> fetchLabel() async {
    await Future.delayed(widget.delay);
    print('fetchLabel call');
    return 'from fetchLabel()';
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      margin: EdgeInsets.symmetric(vertical: 12),
      duration: Duration(milliseconds: 500),
      width: 220,
      height: 120,
      color: label == null ? Colors.white : widget.color,
      child: Center(
        child: Text(label ?? 'fetching...'),
      ),
    );
  }
}


Column(
  children: [
    TestBox(
      delay: Duration(seconds: 1),
      color: Colors.green,
    ),
    TestBox(
      delay: Duration(seconds: 3),
      color: Colors.yellow,
    ),
    TestBox(
      delay: Duration(seconds: 5),
      color: Colors.red,
    ),
  ],
),

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

我有一个Stateful widget,在其中使用html_editor_enhanced插件小部件。这是设置初始消息的唯一方法。

class _SendChatMessageState extends State<SendChatMessage> {
  final _htmlController = HtmlEditorController();

      @override
      void initState() {
        super.initState();
    
          Future.delayed(const Duration(seconds: 3), () {
            _htmlController.setText(widget.chatMessage.message ?? '');
          });
      }

我尝试使用addPostFrameCallback,但它没有起作用,因为JavaScript会生成异常“HTML编辑器仍在加载中,请等待JS评估之前...”


-2

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

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

2
你为什么要在构建小部件后添加延迟? - Chirag Arora
这里完全没有必要使用延迟,即使您没有使用WidgetsBinding.instance.addPostFrameCallback,3秒钟也太长了。 - sitatech

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接