FlutterでWidgetを絶対位置で配置してみる(position: absolute; 風に)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366412/57f5363e-d5b2-d56e-ed07-8116836280d0.png" width=50%>

Flutterで複数のWidgetを配置したいとき、選択肢としてまずColumnやRowが挙げられます。
ColumnやRowでは、Widgetは相対位置で配置されます。つまり、1つ前のWidgetが基準となり、その下にWidgetが追加されます。CSSで言うところの`position: relative;` を指定したようなイメージです。

`position: absolute;`を指定した時のように絶対位置でWidgetを配置したいときは、StackというWidgetと
**①Positioned**
**②Align**
これらのWidgetを組み合わせて使うと簡単です。

***

使い方は以下のように、分かりやすいものとなっています。

## ①Positionedを使ったとき

```dart:main.dart
class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stack(
        children: <Widget>[
          // Positionedで配置
          WidgetA(),
          Positioned(
            top: 10.0,
            left: 10.0,
            width: 100.0,
            height: 100.0,
            child: WidgetB(),
          ),
          Positioned(
            top: 10.0,
            right: 10.0,
            width: 100.0,
            height: 100.0,
            child: WidgetC(),
          ),
          Positioned(
            bottom: 10.0,
            right: 10.0,
            width: 100.0,
            height: 100.0,
            child: WidgetD(),
          ),
          Positioned(
            bottom: 10.0,
            left: 10.0,
            width: 100.0,
            height: 100.0,
            child: WidgetE(),
          ),
        ],
        fit: StackFit.expand,
      ),
    );
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0.0, 0.0),
      color: Colors.white70,
      child: Text('Widget A'),
    );
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0.0, 0.0),
      color: Colors.lightGreen,
      child: Text('Widget B'),
    );
  }
}

// 以下同様に、WidgetC, WidgetD, WidgetE
```
このように、Stackを親Widgetとして、絶対位置で配置することができます。
子Widgetに幅や高さが指定されていない場合は、top, bottom, heightから2つ、left, right, widthから2つの値を指定して、サイズを持たせるようにしましょう。

(この場合は、親WidgetにPaddingをつけるやり方が良いですね....)

## ②Alignを使ったとき
端に余白をつける必要がなく、Widgetが幅・高さを持っているときには、Alignが便利です。

```dart:main.dart
class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stack(
        children: <Widget>[
          // Alignで配置
          WidgetA(),
          Align(
            alignment: Alignment.topLeft,
            child: WidgetB(),
          ),
          Align(
            alignment: Alignment.topRight,
            child: WidgetC(),
          ),
          Align(
            alignment: Alignment.bottomRight,
            child: WidgetD(),
          ),
          Align(
            alignment: Alignment.bottomLeft,
            child: WidgetE(),
          ),
        ],
        fit: StackFit.expand,
      ),
    );
  }
}

class WidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0.0, 0.0),
      color: Colors.white70,
      child: Text('Widget A'),
    );
  }
}

class WidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 100.0,
      height: 100.0,
      child: Container(
        alignment: Alignment(0.0, 0.0),
        color: Colors.lightGreen,
        child: Text('Widget B'),
      ),
    );
  }
}

// 以下同様に、WidgetC, WidgetD, WidgetE
```

以下のように、親Widgetに対して任意の位置に配置することが可能です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366412/f971a008-cc7c-8eff-0a79-3854755aceb5.png" width=50%>