🌱
【Flutter】レンダリング後のWidgetサイズを取得する
経緯
Expanded なのどのフレキシブルな Widget のサイズを取得する必要があった。
Global Key を使用
レンダリングされた Widget を特定するために Global Key を使用する。
※Global Key は一意である必要があったり、メモリ使用量増加にもつながるので慎重な使用が必要。
keyの宣言
final GlobalKey _containerKey = GlobalKey();
keyを指定
Container(
key: _containerKey,
)
サイズの取得
Global Key を使って Widget を特定し、その Widget の RenderBox を取得する。
※RenderBox はレンダリングされたオブジェクトの Size プロパティを持っている。
RenderBoxの取得
final RenderBox? renderBox = _containerKey.currentContext?.findRenderObject() as RenderBox?;
print(renderBox?.size.toString()); // Size(600.0, 600.0)
init 時の注意点
initState()でサイズを取得したい場合は、レンダリング後にサイズ取得を行う必要があるため、addPostFrameCallback()を使用する。
addPostFrameCallback()は引数のコールバック関数をレンダリング後に実行してくれる。
init時
void getContainerSize() {
final RenderBox? renderBox = _containerKey.currentContext?.findRenderObject() as RenderBox?;
setState(() {
containerSize = renderBox?.size ?? Size.zero;
});
}
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => getContainerSize());
}
RenderBox について
RenderBox はプロパティにサイズや位置などを持つ RenderObject のサブクラスです。
RenderObject はレイアウトツリーに挿入されるタイミングで createRenderObject()によって作成される。
位置情報の取得は下記のように行います。
位置の取得
RenderBox renderBox = _containerKey.currentContext.findRenderObject();
Offset position = renderBox.localToGlobal(Offset.zero);
print(position); // Offset(0.0, 100.0)
コードサンプル
コード全文
import 'package:flutter/material.dart';
class RenderingSample extends StatefulWidget {
const RenderingSample({
super.key,
});
State<RenderingSample> createState() => _RenderingSampleState();
}
class _RenderingSampleState extends State<RenderingSample> {
final GlobalKey _containerKey = GlobalKey();
Size containerSize = Size.zero;
void getContainerSize() {
final RenderBox? renderBox = _containerKey.currentContext?.findRenderObject() as RenderBox?;
setState(() {
containerSize = renderBox?.size ?? Size.zero;
});
}
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => getContainerSize());
}
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
color: Colors.blue,
height: 100,
width: double.infinity,
child: const Center(
child: Text(
'Height: 100',
style: TextStyle(
color: Colors.white,
fontSize: 32,
),
),
),
),
Expanded(
child: Container(
key: _containerKey,
color: Colors.red,
child: Center(
child: Text(
'ContainerSize: ${containerSize.width} x ${containerSize.height}\nMediaQuery :${MediaQuery.of(context).size.width} x ${MediaQuery.of(context).size.height}',
style: const TextStyle(
color: Colors.white,
fontSize: 32,
),
),
),
),
),
],
),
);
}
}
Discussion
This is really helpful!
そんなことがあるんですね。知らなかったです。素晴らしい記事をありがとうございます!