Flutter Webで右下ボタンから複数のボタンが出てくるアニメーション

Flutter Webって書いたけど別にスマホでも動く

# こういうやつです

<img src="https://i.gyazo.com/3497dbf8f08784a0e110c8a026ba2f25.gif" width=30%>

# 覚えたこと
`Scaffold`の`floatingActionButton`にはWidgetを自由に指定できる
`StackView`の重ね方
`AnimatedPositioned`で位置を変えるアニメーション


# ソース

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isClose = true;//ボタンを隠すか出すか
  //ボタンを出す時のパラメータ
  //右下のFloatingActionButtonを中心に扇状に出す
  static var _radius = 130.0; //半径
  static var _startRad = pi / 20; //円弧のスタート地点の角度
  static var _endRad = pi / 2 - _startRad;//円弧のエンド地点の角度

  //各ボタンのパラメータ
  var _backFloatingActionButtonParameters = [
    {
      "bottom": 0.0,
      "right": 0.0,
      "elevation": 0.0,
      "color": Colors.redAccent,
    },
    {
      "bottom": 0.0,
      "right": 0.0,
      "elevation": 0.0,
      "color": Colors.greenAccent
    },
    {
      "bottom": 0.0,
      "right": 0.0,
      "elevation": 0.0,
      "color": Colors.purpleAccent,
    },
  ];

  void _tapFloatingActionButton() {
    setState(() {
      _isClose = !_isClose;
      if (_isClose) {
        //閉じるなら一番手前のFloatingActionButtonの下に移動して影を消す
        for (var _backFloatingActionButtonParameter
            in _backFloatingActionButtonParameters) {
          _backFloatingActionButtonParameter["bottom"] = 0;
          _backFloatingActionButtonParameter["right"] = 0;
          _backFloatingActionButtonParameter["elevation"] = 0;
        }
      } else {
        //開くなら一番手前のFloatingActionButtonを中心に扇状に出して影を出す
        for (int i = 0; i < _backFloatingActionButtonParameters.length; i++) {
          //各ボタンの角度を計算
          var rad = i *
                  (_endRad - _startRad) /
                  (_backFloatingActionButtonParameters.length - 1) +
              _startRad;
          //位置を計算
          _backFloatingActionButtonParameters[i]["bottom"] = _radius * cos(rad);
          _backFloatingActionButtonParameters[i]["right"] = _radius * sin(rad);
         //影をデフォルト値の6にする
          _backFloatingActionButtonParameters[i]["elevation"] = 6.0;
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    //FloatingActionButtonの下に隠れるボタンの配列を用意
    List<Widget> floatingActionButtons =
        List.generate(this._backFloatingActionButtonParameters.length, (i) {
      var param = this._backFloatingActionButtonParameters[i];
      return AnimatedPositioned(
        duration: Duration(milliseconds: 200),
        right: param["right"],
        bottom: param["bottom"],
        child: FloatingActionButton(
          elevation: param["elevation"],
          hoverElevation: param["elevation"],
          focusElevation: param["elevation"],
          highlightElevation: param["elevation"],
          backgroundColor: param["color"],
          onPressed: () {
            print("pressed");
          },
        ),
      );
    })//最後に一番手前用のFloatingActionButtonを足す
          ..add(FloatingActionButton(
            backgroundColor: Colors.blueAccent,
            onPressed: () {
              _tapFloatingActionButton();
            },
          ));

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SafeArea(
        child: Container(
          color: Colors.white,
        ),
      ),
      //ContainerでfloatingActionButtonの領域を用意
      floatingActionButton: Container(
        width: 2 * _radius,
        height: 2 * _radius,
        //Stackで右下に配置
        child: Stack(
          alignment: Alignment.bottomRight,
          children: floatingActionButtons,
        ),
      ),
    );
  }
}

```

# 最後に

Flutter面白くて一生遊んでられそう