FlutterでWidgetの位置とサイズを取得する

#FlutterでWidgetの位置やサイズを取得したい
検索しても地図上の位置を取得するのばっかヒットしてつらい

###GlobalKeyを使ってRenderBoxを取得する
[参考サイト:https://medium.com/@diegoveloper/flutter-widget-size-and-position-b0a9ffed9407](https://medium.com/@diegoveloper/flutter-widget-size-and-position-b0a9ffed9407)

```dart:TestState.dart
//class TestWidgetは省略

GlobalKey globalKey = GlobalKey(); //←これが重要

class _TestState extends State<TestWidget>{
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Expanded(
          child: RaisedButton(
            child: Text("test"),
            onPressed: (){
               //↓変数はRenderBoxで宣言（.findRenderObject()で帰ってくるのは"RenderObject"のため
              RenderBox box = globalKey.currentContext.findRenderObject();
              print("ウィジェットのサイズ :${box.size}");
              print("ウィジェットの位置 :${box.localToGlobal(Offset.zero)}");
            },
          ),
        ),
        Center(
          child: Text("このウィジェットのサイズ",
            key: globalKey, //←知りたいWidgetにGlobalKeyをセット
          ),
        ),
      ],
    );
  }
}
```
**RenderBox** box = globalKey.**currentContext.findRenderObject()**;
↑
これで`GlobalKey`をセットした`Widget`を元に描画された`RenderBox`インスタンスを取得出来ます。（返ってくるのは`RenderObject`なので変数の宣言は`RenderBox`にする）

**結果**
>ウィジェットのサイズ :Size(88.0, 48.0)
ウィジェットの位置 :Offset(0.0,24.0)

.localeToGlobal(Offset)で取得している位置は、ウィジェットの左上の点
引数のOffsetがゼロでない場合、その分の座標が足される

###注意点
**GlobalKeyを付けたWidgetが一度もBuildされていない場合、RenderBoxは取得出来ない**
一度も`Widget`が`build`されていない場合、`RenderBox`はそもそも描画されていないので取得出来ません。（大きさが可変の`Widget`を考えてみれば分かる）

```dart
// 失敗するやり方
GlobalKey globalKey = GlobalKey();
class _TestState extends State<TestWidget> {
  //サイズと位置を取得するメソッド
  String _getLocaleAndSize() {
    RenderBox box = globalKey.currentContext.findRenderObject();
    return "ウィジェットのサイズ :${box.size}\n"
        "ウィジェットの位置 :${box.localToGlobal(Offset.zero)}";
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Expanded(
          child: RaisedButton(
            child: Text(_getLocaleAndSize()), // ←ボタンのタイトルにする
            onPressed: () {
              print(_getLocaleAndSize);
            },
          ),
        ),
        Center(
          child: Text(
            "このウィジェットのサイズ",
            key: globalKey,
          ),
        ),
      ],
    );
  }
}
```

**結果**

>エラー
>>The method 'findRenderObject' was called on null.
Receiver: null
Tried calling: findRenderObject()

###回避法
`WidgetsBinding.instance.addPostFrameCallback(Function callback)`を使う
`WidgetsBinding.addPostFrameCallback`を使うと**Build終了時に実行する処理**が書けます

```dart

var globalKey = GlobalKey();

class _TestState extends State<TestWidget> {
  String _getLocaleAndSize() {
    RenderBox box = globalKey.currentContext.findRenderObject();
    return "ウィジェットのサイズ :${box.size}\n"
        "ウィジェットの位置 :${box.localToGlobal(Offset.zero)}";
  }
  String _text;//←変数を用意
  @override
  Widget build(BuildContext context) {
    if (_text == null) // Build時、テキストがnullの場合↓を実行
      WidgetsBinding.instance.addPostFrameCallback((cb){
        setState(() {
          _text = _getLocaleAndSize();
        });
      });
    return Column(
      children: <Widget>[
        Expanded(
          child: RaisedButton(
            child: Text(_text ?? "テキストはまだない"),
            onPressed: () {
              print(_getLocaleAndSize);
            },
          ),
        ),
        Center(
          child: Text(
            "このウィジェットのサイズ",
            key: globalKey,
          ),
        ),
      ],
    );
  }
}
```
**注意**
`WidgetsBinding.addPostFrameCallback`は他にも色々使えて便利ですが、`build`時に使用するときは無限ループしないように気をつけましょうね～