Flutterのカスタムウィジェット(GestureDetector編)

Flutterでカスタムウィジェットを作るには主にCustomPaintウィジェットとGestureDetectorウィジェットを使う。  
CustomPaintウィジェットについてはこちら

https://qiita.com/WAsub/items/2a606e64d7fcc679234e

## GestureDetectorウィジェット
タップ、ロングタップ、ドラッグなどのジェスチャーを検知して処理をさせることができるウィジェット。
このウィジェットは下記の記事がすごくわかりやすいので、詳しくは書かない。

[Flutter でタップやドラッグ、ピンチや回転などのジェスチャー操作を処理する](https://cbtdev.net/flutter-gesture-detector/)

### サンプルコード(未完成だが一応使える)
以下のサンプルコードはカスタムウィジェットとしてコンポーネント化したもの。
`2021/07/12現在、実際に使用してみると反応が悪く感じるので今後も改良していく。
また、細かいところをきちんとコンポーネント化できていないので気が向いたら直す。`

```dart
SwipeContainer(
    /** deviceHeightとdeviceWidthは
     *  LayoutBuilderなどから端末の画面サイズ を割り出し格納したもの*/
    height: deviceHeight * 0.9, 
    width: deviceWidth,
    swipB: 30,
    color: Theme.of(context).accentColor, // テーマカラーのアクセントカラー
    child: /** ここにスワイプコンテナ内に入れる要素を書く */
);
```
上記のような感じで使う。


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

class SwipeContainer extends StatefulWidget{
  double height;
  double width;
  double swipB; // コンテナ下からどのくらいの位置か。(下でもうちょいくわしく)
  Widget child;
  Color color;
  
  SwipeContainer({
    this.height,
    this.width,
    this.swipB,
    this.child,
    this.color,
  });
  @override
  SwipeContainerState createState() => SwipeContainerState();
}

class SwipeContainerState extends State<SwipeContainer> {
  @override
  Widget build(BuildContext context) {
    /** 何も引数を入れなかった場合の初期値 */
    widget.height = widget.height == null ? 500.0 : widget.height;
    widget.width = widget.width == null ? null : widget.width;
    widget.swipB = widget.swipB == null ? 30.0 : widget.swipB;
    widget.child = widget.child == null ? null : widget.child;
    widget.color = widget.color == null ? Colors.blue : widget.color;
    /** ここからスワイプコンテナ */
    return AnimatedPositioned(
        duration: Duration(milliseconds: 200),
        /** 最初はコンテナのほとんどを隠しているのでマイナスになるようにする */
        bottom: -(widget.height - widget.swipB), // seipB分上端が飛び出すように
        child: GestureDetector(
          /** 上下方向のドラッグを検出するやつ */
          onVerticalDragUpdate: (DragUpdateDetails details) {
            setState(() {
              // 上スワイプでコンテナすべてを表示
              // 正し、このコンテナは四隅を丸めていて、
              // 下の丸みは見せたくないので-20をしている。
              if (details.delta.dy < -10) { 
                widget.swipB = widget.height - 20; }
              // 下スワイプで元の位置にもどす
              if (details.delta.dy > 10) { 
                widget.swipB = 30; }
            });
          },
          /** スワイプコンテナ */
          child: Container(
            width: widget.width,
            height: widget.height + 20,
            decoration: BoxDecoration(
              color: widget.color,
              borderRadius: BorderRadius.circular(20),
            ),
            child: Column(children: [
              // なんかそれっぽい棒と隙間開ける用
              Container(
                height: 50,
                alignment: Alignment.topCenter,
                padding: EdgeInsets.only(top: 5),
                child: Container(
                  height: 4,
                  width: 80,
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(2),
                  ),
                ),
              ),
              widget.child,
            ]),
          ),
        ),
    );
  }
}
```
## 参考資料
[Flutterのカスタムウィジェット(CustomPaint編)](https://qiita.com/WAsub/items/2a606e64d7fcc679234e)
[FlutterでフルスクラッチでWidgetを作る時に知っておきたいこと](FlutterでフルスクラッチでWidgetを作る時に知っておきたいこと)