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