はじめに
Flutterでウィジェットをずらして重ねる方法についてご紹介します。
ウィジェットの重なりをコントロールすることで画面内での複雑なUI表現が可能になります。
注意
本記事の内容については、Flutter2についての内容です。
紹介されているClipBehavior
等の振る舞いについて、Flutter3以降大きな変更が加えられているようです。
目標
複数のウィジェットをずらして重ねた状態で表示する。
実装
FlutterにはStack
という子要素のウィジェットを重ねてくれるウィジェットが存在します。
子要素の重なり方は、リストは後の要素が前の要素の上に重なるように表示されます。
Stack(
children: [
Container(
width: 100,
height: 50,
color: Colors.blue,
),
Container(
width: 30,
height: 30,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
],
),
このままでは上に重なるウィジェットの位置を細かく調節することができません。
そこでPositioned
という子要素の位置を指定するウィジェットを使用します。
Positioned(
top: 0,
left: 0,
child: Container(
width: 30,
height: 30,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
),
このときPositioned
内に指定する位置の値は、重なりの下のウィジェットが基準となります。
つまりtop: 0, left: 0
を指定した場合、下側のウィジェットの左上にピタリと重なるように上側のウィジェットは配置されます。
位置に指定する値は負の数を取ることができるので、ウィジェットをずらして重ねたい場合、例えばtop: -10, left: -10
のようにマイナスの数値を指定すれば良いことになります。
Positioned(
top: -10,
left: -10,
child: Container(
width: 30,
height: 30,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
),
ところがこのコードを実行すると、次の図のようにはみ出した部分が切り取られたように表示されてしまいます。
この現象の原因は、Stack
ウィジェットのclipBehavior
プロパティにClip.hardEdge
という値がデフォルトで指定されていることです。
clipBehavior
プロパティでは、ウィジェットが親要素のウィジェットの領域からオーバーフローする場合の挙動を指定することができます。
はみ出した部分が切り取られないように、値をClip.none
に変更します。
Stack(
clipBehavior: Clip.none,
children: [
Container(
width: 100,
height: 50,
color: Colors.blue,
),
Positioned(
top: -10,
left: -10,
child: Container(
width: 30,
height: 30,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
),
],
),
このコードを実行した結果は次のようになります。
ウィジェットをずらして重ねることができました。
おわりに
本記事ではFlutter2において、画面上に複数のウィジェットをずらして重ねる実装方法についてご紹介しました。
この方法を応用すると、例えば未読や通知バッジを任意のウィジェットの上に表示することが可能になります。