[Flutter] OffstageとStackでWidgetを切り替える

##はじめに
この記事では以下の画像のような,ボタンを押すことでWidgetを切り替える方法について説明しています。

![2020-10-06 19.42のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/b33f0b1b-0740-8ec6-d3b8-43dcb0a7dd96.jpeg)　![2020-10-06 19.44のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/7371492c-6343-1396-121c-06c56a7b8658.jpeg)




##この記事が参考になるかもしれない人
- コピペで動くソースコードをいじることによってFlutterについて学習したい人
- FlutterでWidgetの切り替えを行いたい人
- StackでWidgetを重ねることによる実装が行いたい人
- Offstageによる実装を行いたい人
- 自分

##前提知識
- Columnで鉛直方向にWidgetを並べることができる。
- ` mainAxisAlignment: MainAxisAlignment.center`でColumnに対し真ん中で鉛直方向に並べさせることができる。
- StackでWidgetを重ねることができる。(Columnは鉛直方向,Rowは水平方向)
- StatefulWidgetは変数の変更など動的な操作をする時に使う。

##1.OffStageでWidgetを表示したり非表示にしたりできる
OffstageはレイアウトWidgetであり、表示/非表示を設定したいWidgetを**child**に入れる。また,**offstage**に真偽値を指定し、**false**の時に表示される。しかし、false/trueはいずれも固定されているものなので,表示/非表示を設定したいのであれば,ここにはbool型の変数を用いるべきだろう。
また,注意したいのがOffStageに格納されたWidgetは非表示にされた場合子要素のWidget自体が存在していないものとして扱われる。つまり、Columnなどの連続したものの中の一つにOffstageを入れた場合,非表示となったWidgetの部分は他のWidgetが詰めて配置されることとなる。


```Dart
Offstage(
              offstage: show,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.red,
                ),
              )
```

##2.Offstageだと詰められてしまうので,Stackを用意して対策する。
上述した通り,Offstageで書いた要素はパラメータ**offstage**がtrueの時元から存在していなかったものとして扱われてしまう。なので,その時には別のWidget（たとえば子要素が何もないContainer）を用意する必要がある。

```Dart
Stack(
              children: <Widget>[
            Offstage(
              offstage: show,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.red,
                ),
              ),
            Offstage(
              offstage: !show,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.blue,
                ),
              ),
              ],
            ),
```

Stackの子要素集合にそれぞれOffstageWidgetのパラメータ**offstage**が偽の時と真の時を用意することで、配置がずれることなく表示/非表示を設定することができる。

##ソースコード
コピペで動きます。(2020.10.6)

```Dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool show = false;
  void showChange() {
    setState(() {show = !show;});
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Stack(
              children: <Widget>[
            Offstage(
              offstage: show,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.red,
                ),
              ),
            Offstage(
              offstage: !show,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.blue,
                ),
              ),
              ],
            ),
            Container(
               width: 100,
               height: 100,
               child: RaisedButton(
                 child: Text("変更"),
                 onPressed: showChange
                 ),
              ),
            ],
          ),
         ),
        ),
      );
  }
}
```