flutter开发实战-第一帧布局完成回调实现
在开发中,我们有时候需要在第一帧布局完成后调用一些相关的方法。这里记录一下是实现过程。
Flutter中有多种不同的Binding,每种Binding都负责不同的功能。下面是Flutter中常见的Binding:
这里简单说明一下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开发实战-第一帧布局完成回调实现
学习记录,每天不停进步。