22
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

普段Flutterでレスポンシブな対応をする場合、MediaQueryを用いて以下のように書いておりました。

Widget build(BuildContext context) {
  final Size size = MediaQuery.sizeOf(context);
  return Scaffold(
    appBar: AppBar(
      title: const Text('MediaQuery Demo'),
    ),
    body: SizedBox(
      width: size.width * 0.8,
      height: size.height * 0.1,
      child: Container(
        color: Colors.amber,
      ),
    ),
  );
}

ただ、もう少し最適なウィジェットが公式で用意されていました。

FractionallySizedBox

FractionallySizedBoxウィジェットを用いると、以下の様にいちいちメディアクエリを書かなくて良くなり、さらにこのウィジェットは少し応用を効かせることも可能です。
さらに、パラメーターにalignmentを指定できるため、簡単に簡単に中央寄せの設定も可能です。

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('MediaQuery Demo'),
    ),
    body: SizedBox.expand(
      child: FractionallySizedBox(
        alignment: Alignment.topCenter,
        widthFactor: 0.8,
        heightFactor: 0.1,
        child: Container(
          color: Colors.amber,
        ),
      ),
    ),
  );
}

ちょっとした応用

公式などにも記載がありますが、いくつか応用ができそうでした。

1. 余白として使う

FractionallySizedBoxはchildパラメーターがrequiredではないため、空の余白としても使えます。

FractionallySizedBox(
    alignment: Alignment.topCenter,
    heightFactor: 0.1, // 高さの余白のみ指定
),

2. FlexibleなどでラップしてColumnやRowで使える

FractionallySizedBoxをそのままRowやColumnウィジェットで使ってしまうと、よくみる
Failed assertion: line 1966 pos 12: 'hasSize'のエラーに陥ってしまいます。しかし、Flexibleでラップすることで簡単に使うことが可能です。

Column(
  children: [
    Flexible(
      child: FractionallySizedBox(
        alignment: Alignment.topCenter,
        widthFactor: 0.8,
        heightFactor: 0.1,
        child: Container(
          color: Colors.amber,
        ),
      ),
    ),
    // FractionallySizedBox(
    //   alignment: Alignment.topCenter,
    //   widthFactor: 0.8,
    //   heightFactor: 0.1,
    //   child: Container(
    //     color: Colors.amber,
    //   ),
    // ),
  ],
),

3. 簡易アニメーション

AnimatedFractionallySizedBoxを使うことで、簡易的にアニメーションの実装もすることができます。
領域の伸び縮みをするアニメーションや、widthFactor, heightFactorを動的にしたい場合に有効です。

SizedBox.expand(
  child: Column(
    children: [
      Flexible(
        child: AnimatedFractionallySizedBox(
          alignment: Alignment.topCenter,
          widthFactor: _sliderValue,
          heightFactor: 0.2,
          duration: const Duration(milliseconds: 500),
          curve: Curves.easeInOut,
          child: Container(
            color: Colors.amber,
          ),
        ),
      ),
      const Flexible(
        child: FractionallySizedBox(
          heightFactor: 0.1,
        ),
      ),
      ElevatedButton(
        onPressed: () {
          setState(() {
            if (_sliderValue < 1.0) {
              _sliderValue += 0.05;
            } else {
              _sliderValue = 0.1;
            }
          });
        },
        child: const Text('Animation'),
      ),
    ],
  ),
),

注意点

今回の記事で、MediaQuery.sizeOfよりFractionallySizedBoxを推奨しましたが、もしこれから移行する方はお気をつけください。
FractionallySizedBoxheightFactor: 0.5は、親要素の対する50%の高さですが、MediaQuery.sizeOf(context).height * 0.5は基本的に画面全体に対する50%となります。
この記事と1枚目の画像と2枚目の画像を比較していただければ若干差があることに気づけると思います。
そのため、一概にMediaQueryがダメというわけではなく、用途に応じて使い分けていただければと思います。

MediaQuery(1枚目) FractionallySizedBox(2枚目)
22
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?