flutter开发实战-第一帧布局完成回调实现

flutter开发实战-第一帧布局完成回调实现

在开发中,我们有时候需要在第一帧布局完成后调用一些相关的方法。这里记录一下是实现过程。

Flutter中有多种不同的Binding,每种Binding都负责不同的功能。下面是Flutter中常见的Binding:

这里简单说明一下WidgetsBinding

一、WidgetsBinding

WidgetsBinding:负责管理Flutter应用程序的生命周期,包括启动、暂停、恢复和停止等。

WidgetsBinding它用于监听用户设置的更改,如语言的修改。 不仅如此, WidgetsBinding 否是 Widgets 与 Flutter 引擎之间通信的桥梁,有两个主要的功能:

  * 1 负责处理Widgets结构变更的过程;

  * 2 第二个是触发渲染事件。

一些小组件的结构更改是 BuildOwner 来完成的,它跟踪需要重建的小部件,并处理应用于整个小部件结构的其他任务。

二、实现第一帧布局完成后调用相关方法

在WidgetsBinding中,我们可以看到endOfFrame方法,源码如下

复制代码
/// Returns a Future that completes after the frame completes.
  ///
  /// If this is called between frames, a frame is immediately scheduled if
  /// necessary. If this is called during a frame, the Future completes after
  /// the current frame.
  ///
  /// If the device's screen is currently turned off, this may wait a very long
  /// time, since frames are not scheduled while the device's screen is turned
  /// off.
  Future<void> get endOfFrame {
    if (_nextFrameCompleter == null) {
      if (schedulerPhase == SchedulerPhase.idle) {
        scheduleFrame();
      }
      _nextFrameCompleter = Completer<void>();
      addPostFrameCallback((Duration timeStamp) {
        _nextFrameCompleter!.complete();
        _nextFrameCompleter = null;
      });
    }
    return _nextFrameCompleter!.future;
  }

方法中描述如下

复制代码
该方法返回在帧完成后完成的Future。
如果在帧之前调用的时候,则会立即调度帧。如果在帧期间调用此操作,则Future将在当前帧完成后调用。
如果设备的屏幕当前已关闭,这可能会等待很长时间。

所以我们需要在initState中调用相关方法

复制代码
WidgetsBinding.instance.endOfFrame.then(
          (value) {
        if (mounted) {
           // TODO调用相关方法
        }
      },
    );

实现第一帧布局完成后调用完成代码如下

复制代码
class AfterLayoutPage extends StatefulWidget {
  const AfterLayoutPage({super.key});

  @override
  State<AfterLayoutPage> createState() => _AfterLayoutPageState();
}

class _AfterLayoutPageState extends State<AfterLayoutPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AfterLayoutPage'),
      ),
      body: Container(
        color: Colors.blueGrey,
      ),
    );
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    WidgetsBinding.instance.endOfFrame.then(
          (value) {
        if (mounted) {
          showHelloWorld();
        }
      },
    );
  }

  void showHelloWorld() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          content: const Text('Hello World'),
          actions: <Widget>[
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('DISMISS'),
            )
          ],
        );
      },
    );
  }
}

可以将该实现包装成一个Mixin

复制代码
import 'dart:async';

import 'package:flutter/widgets.dart';

mixin AfterLayoutMixin<T extends StatefulWidget> on State<T> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.endOfFrame.then(
      (_) {
        if (mounted) afterFirstLayout(context);
      },
    );
  }

  FutureOr<void> afterFirstLayout(BuildContext context);
}

调整后代码如下

复制代码
class AfterLayoutPage extends StatefulWidget {
  const AfterLayoutPage({super.key});

  @override
  State<AfterLayoutPage> createState() => _AfterLayoutPageState();
}

class _AfterLayoutPageState extends State<AfterLayoutPage> with AfterLayoutMixin<AfterLayoutPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AfterLayoutPage'),
      ),
      body: Container(
        color: Colors.blueGrey,
      ),
    );
  }

  @override
  void afterFirstLayout(BuildContext context) {
    // Calling the same function "after layout" to resolve the issue.
    showHelloWorld();
  }

  void showHelloWorld() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          content: const Text('Hello World'),
          actions: <Widget>[
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('DISMISS'),
            )
          ],
        );
      },
    );
  }
}

三、小结

flutter开发实战-第一帧布局完成回调实现

学习记录,每天不停进步。

相关推荐
疯狂打码的少年2 小时前
【数据库技术】SQL嵌套查询(IN/EXISTS/ANY/ALL)
数据库·笔记·sql
凯尔萨厮2 小时前
Java学习笔记十四(网络通信)
笔记·学习
AAA代码批发商3 小时前
DAYS 38 TCP并发服务器模型详解
linux·网络·笔记·学习
启观川3 小时前
Python基础-第 16 章 综合案例:客户信息管理系统
开发语言·笔记·python·正则表达式
WK100%3 小时前
LeetCode双题:滑动窗口破解最小子数组
c++·经验分享·笔记·算法
sheeta19983 小时前
LeetCode 每日一题笔记 日期:2026.09.02 题目:3875.构造奇偶一致的数组 I
笔记·算法·leetcode
风123456789~3 小时前
【架构专栏】4.7 信息安全的抗攻击技术 3/4
笔记·系统架构设计
tju新生代魔迷4 小时前
Verilog HDL 学习笔记(十二)| 第12章 用户自定义原语(UDP)
笔记·学习·udp
摇滚侠4 小时前
《SpringBoot 3:入门与应用实战》第 13 章 整合 MyBatis MyBatis 概述 阅读笔记 37
spring boot·笔记·mybatis
末代iOS程序员华仔4 小时前
Guideline 5.6 - Developer Code of Conduct
flutter·ios·swift