はじめに
Stackについて基礎を学んだので記事にしました。
目次
基本
Stackのchildrenに指定したWidgetを順番に重ねていく。

Container(
width: 300,
height: 500,
color: Colors.white,
child: Stack(
children: [
Container(
width: 200,
height: 200,
color: Colors.red,
),
Container(
width: 100,
height: 100,
color: Colors.blue,
),
Container(
width: 50,
height: 50,
color: Colors.green,
),
]
),
)
Stackのalignmentを指定すると、その指定通りにwidgetが配置される。 下記はAlignmentDirectional.bottomCenterを指定したときの画像。
Positioned Widgetを使う
Stackに並べるwidgetをPositionedで囲うと指定した位置に配置できる。

Container(
width: 300,
height: 500,
color: Colors.white,
child: Stack(children: [
Positioned(
top: 20,
left: 20,
child: Container(
width: 200,
height: 200,
color: Colors.red,
),
),
Positioned(
top: 50,
right: 50,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
),
Positioned(
bottom: 0,
left: 50,
child: Container(
width: 50,
height: 50,
color: Colors.green,
),
),
]),
),
※topとbottom、またはleftとright両方に値を指定すると下記のような感じで引き伸ばされる。
// 該当部分のみ抜粋
Positioned(
top: 20,
left: 20,
bottom: 20,
child: Container(
width: 200,
height: 200,
color: Colors.red,
),
),
またPositioned.fillとするとStack全体を覆うこともできる。
Clip系と組み合わせる
Clip系のWidgetと組み合わせるとさらにカスタマイズできるので紹介します。
ClipRect
ClipRectはwidgetを矩形で切り抜けます。
Stackと組み合わせると以下の画像のようなことができます。

ソースは以下です。
Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.red,
),
),
Positioned.fill(
child: ClipRect(
clipper: RectClipper(),
child: Container(
color: Colors.blue,
),
),
),
]
)
.....
class RectClipper extends CustomClipper<Rect> {
@override
Rect getClip(Size size) {
return Rect.fromLTRB(20, 20, size.width - 20, size.height - 20);
}
@override
bool shouldReclip(covariant CustomClipper oldClipper) {
return false;
}
}
青と赤は両方とも、Positioned.fillで大きさを同じにしていますが、青の方は端から20ずつカットしました。
ClipRectは下記のような書き方もできますが、Positioned.fillの中だとうまく機能しませんでした。
ClipRect(
child: Align(
alignment: Alignment.center,
widthFactor: 0.4,
heightFactor: 0.5,
child: Container(
color: Colors.blue,
),
),
),
ClipRRect
角丸で切り抜くと下記のようになります。
Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.red,
),
),
Positioned.fill(
child: ClipRRect(
borderRadius: BorderRadius.circular(100),
child: Container(
color: Colors.blue,
),
),
),
]
)
ClipOval
楕円で切り抜くと下記のようになります。
Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.red,
),
),
Positioned.fill(
child: ClipOval(
child: Container(
color: Colors.blue,
),
),
),
]
)
ClipPath
ClipPathを使うと、指定したパス通りに切り抜けます。
Stack(
children: [
Positioned.fill(
child: Container(
color: Colors.red,
),
),
Positioned.fill(
child: ClipPath(
clipper: FreeClipper(),
child: Container(
color: Colors.blue,
),
),
),
]
)
・・・
class FreeClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
final path = Path();
path.moveTo(0, 0);
path.lineTo(size.width / 2, 0);
path.lineTo(size.width / 2, size.height / 2);
path.lineTo(size.width, size.height / 2);
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
path.lineTo(0, 0);
return path;
}
@override
bool shouldReclip(covariant CustomClipper oldClipper) {
return false;
}
}
参考文献




