Flutterレイアウトシリーズのその他の記事
- Stackの使い方
- Flutterのレイアウトを理解する
- FlutterレイアウトのFlex、Row、Column、Wrap、Stack
- FlutterレイアウトのExpanded、Flexible、Spacer
- FlutterのBoxConstraintsを理解する
Overlayとは、言葉の通り、Widgetの上に被せるウェジェット部品とのことです。代表的なウェジェットはTooltipです。この記事はOverlayを使用、理解するため書いたものです。
※本記事は下記のZenn本にまとめました。
レンダリング(rendering)
Overlayを使用するには、Widgetのサイズ、offsetの値が必要です。そこで、contextのfindRenderObject()メソッドからrenderingを取得することが可能です。
RenderObject? renderObject = context.findRenderObject();
if (renderObject != null && renderObject is RenderBox) {
print(renderObject.size);
print(renderObject.localToGlobal(Offset.zero));
}
BuildContextの取得
UIツリーのScaffoldなど親ウェジェットを使うとき、contextは一番上層であるScaffoldのものが多いですが、ウェジェットを分離して、子ウェジェットのcontextを取得することも可能ですが、Builderウェジェットを使い、各自のContextを取得することも可能です。
例:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('HomePage'),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("テキスト"),
Builder(
builder: (BuildContext ctx) => GestureDetector(
onTap: () {
printInfo(ctx);
},
child: Container(
padding: const EdgeInsets.all(3),
child: const Text(
"context",
style: TextStyle(color: Colors.red),
),
),
),
),
],
),
),
);
}
void printInfo(BuildContext context) {
RenderObject? renderObject = context.findRenderObject();
if (renderObject != null && renderObject is RenderBox) {
print(renderObject.size);
print(renderObject.localToGlobal(Offset.zero));
}
}
Overlayの使用
上記の方法でoffsetを取得し、OverlayStateにOverlayEntryを追加することができます。Overlayの作成は下記の流れです。
- OverlayStateの取得
final OverlayState? overlayState = Overlay.of(context);
- OverlayEntryの作成
// offset
Offset targetOffset = Offset.zero;
RenderObject? renderObject = context.findRenderObject();
if (renderObject != null && renderObject is RenderBox) {
targetOffset = renderObject.localToGlobal(Offset.zero);
}
final OverlayState? overlayState = Overlay.of(context);
if (overlayState == null) return;
// OverlayEntryの作成
OverlayEntry entry = OverlayEntry(
builder: (BuildContext context) => Positioned(
width: 50,
height: 50,
left: targetOffset.dx,
top: targetOffset.dy,
child: GestureDetector(
onTap: removeEntry,
child: const ColoredBox(
color: Colors.red,
),
),
),
);
- OverlayEntryのinsert
overlayState.insert(entry);
- Overlayの取り消し
void removeEntry() {
if (_entry != null) {
_entry!.remove();
_entry = null;
}
}