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开发实战-第一帧布局完成回调实现

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

相关推荐
Suwg20918 分钟前
《手写Mybatis渐进式源码实践》实践笔记(第七章 SQL执行器的创建和使用)
java·数据库·笔记·后端·sql·mybatis·模板方法模式
胡西风_foxww28 分钟前
【ES6复习笔记】let 和 const 命令(1)
笔记·学习·es6·const·let
胡西风_foxww29 分钟前
【ES6复习笔记】Spread 扩展运算符(8)
前端·笔记·es6·扩展·运算符·spread
红色的山茶花2 小时前
YOLOv9-0.1部分代码阅读笔记-anchor_generator.py
笔记·深度学习·yolo
m0_748250032 小时前
【STM32】F103ZET6开发板----笔记01
笔记·stm32·嵌入式硬件
1101 11012 小时前
STM32-笔记16-定时器中断点灯
笔记·stm32·单片机
旺旺大力包3 小时前
【 Git 】git 的安装和使用
前端·笔记·git
江上清风山间明月4 小时前
flutter bottomSheet 控件详解
android·flutter·底部导航·bottomsheet
m0_689618284 小时前
数学建模助力干细胞研究,配体纳米簇如何影响干细胞命运
笔记·数学建模
羊村懒哥5 小时前
tomcat-安装笔记(包含虚拟主机配置)
java·笔记·tomcat