Flutter 開発の実践 - 最初のフレーム レイアウト完了コールバックの実装
開発中、最初のフレーム レイアウトが完了した後に、いくつかの関連メソッドを呼び出す必要がある場合があります。ここには実装プロセスが記録されます。
Flutter にはさまざまなバインディングがあり、それぞれのバインディングが異なる機能を担当します。Flutter の一般的なバインディングは次のとおりです。
ここでは WidgetsBinding について簡単に説明します。
一、ウィジェットバインディング
WidgetsBinding: 開始、一時停止、再開、停止など、Flutter アプリケーションのライフ サイクルの管理を担当します。
WidgetsBinding 言語の変更など、ユーザー設定の変更を監視するために使用されます。それだけではなく、WidgetsBinding は Widget と Flutter エンジンの間の通信のブリッジであり、2 つの主な機能があります:
* 1 は Widget 構造の変更のプロセスを処理する責任を負います;
* 2 2 つはレンダリング イベントをトリガーすることです。
一部のウィジェット構造変更は BuildOwner によって行われ、BuildOwner は再構築が必要なウィジェットを追跡し、ウィジェット構造全体に適用される他のタスクを処理します。
2. 最初のフレームレイアウトが完了したら、関連するメソッドを呼び出します。
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'),
)
],
);
},
);
}
}
3. まとめ
Flutter開発実践 - フレームレイアウト完了コールバックの実装を優先
勉強して記録し、日々改善を続けてください。