【Flutter】Rowの子Widgetの高さを揃える方法
はじめに
下記の画像みたいな
- それぞれの行の高さが同じなTable
- 背景色が崩れない
を実装したかったのですが、かなり沼にハマったのでメモを残します。
スクリーンショット => 成功画像
スクリーンショット => 失敗画像
解決したcode全文
実装コード => IntrinsicHeight
import 'package:flutter/material.dart';
class IntrinsicHeightScreen extends StatelessWidget {
const IntrinsicHeightScreen({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_customTableRow("会社名", "hogehoge株式会社", isFirst: true),
_customTableRow("住所", "東京都〇〇〇〇"),
_customTableRow("電話番号", "03-××××-××××"),
_customTableRow("沿革", """令和2年4月:hogehoge株式会社設立
令和2年8月:東京に○○店をオープン
令和3年6月:社名を○○へ変更
令和3年5月:売上高1000億円を達成
令和3年12月:マザーズへ株式を上場
"""),
],
),
)),
);
}
Widget _customTableRow(String firstText, String secondText, {bool isFirst = false}) {
return Container(
decoration: (isFirst)
? BoxDecoration(border: Border.all(color: const Color(0XFF000000)))
: const BoxDecoration(
border: Border(
left: BorderSide(color: Color(0XFF000000)),
right: BorderSide(color: Color(0XFF000000)),
bottom: BorderSide(color: Color(0XFF000000)),
),
),
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 1,
child: ColoredBox(
color: const Color(0XFFD3D3D3),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 10.0),
child: Text(firstText),
),
),
),
const VerticalDivider(color: Color(0XFF000000), width: 1),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 10.0),
child: Text(secondText),
),
)
],
),
),
);
}
}
解説
IntrinsicHeight
クラスが解決してくれました。
このIntrinsicHeight
クラスでRow
クラスを囲むと高さを合わせてくれます。
IntrinsicHeightクラスの説明(Flutter.dev引用)
子ウィジェットのサイズを、子ウィジェット固有の高さにするウィジェットです。
このクラスは、例えば高さが無制限で使用できる場合に、無限に拡張しようとする子ウィジェットを、より合理的な高さにサイズ変更させたい場合に有用です。
このウィジェットが子に渡す制約は、親の制約に従います。そのため、制約が子の最大固有高さを満たすのに十分大きくない場合、子は他の場合より小さい高さを取得します。同様に、高さの最小制約が子の最大固有高さより大きい場合、子には他の場合より大きな高さが与えられます。
ただし下記の説明の通り、処理が重たいので使い過ぎには注意が必要みたいです。
IntrinsicHeightクラスの注意点(Flutter.dev引用)
このクラスは、最終的なレイアウトフェーズの前に投機的なレイアウトパスを追加するため、比較的高価です。可能な限り、このクラスの使用は避けてください。最悪の場合、このウィジェットは、ツリーの深さが O(N²) になるようなレイアウトになる可能性があります。
解決するまでの経緯
Table
クラスを使って実装を試みる
初めはTable
クラスを使って実装しようとしてました。
少し調べて実装したところ、下のスクショ画像のように「お、うまくいくじゃん。Table便利!」って思ってたんです。
実装コード => Table
import 'package:flutter/material.dart';
class IntrinsicHeightScreen extends StatelessWidget {
const IntrinsicHeightScreen({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Table(
columnWidths: const <int, TableColumnWidth>{
0: FlexColumnWidth(1),
1: FlexColumnWidth(2),
},
border: TableBorder.all(),
children: [
_customTableRow("会社名", "hogehoge株式会社"),
_customTableRow("住所", "東京都〇〇〇〇"),
_customTableRow("電話番号", "03-××××-××××"),
],
),
),
),
),
);
}
TableRow _customTableRow(String firstText, String secondText) {
return TableRow(
children: [
Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFFD3D3D3),
child: Text(firstText),
),
Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFFFFFFFF),
child: Text(secondText),
),
],
);
}
}
スクリーンショット => Tableで実装
文字数が長いと背景色が...
上のコードにもう一行沿革
というフィールドを追加して、長めのテキストを入れてみました。
すると...
スクリーンショット => 背景色が...
沿革
の背景色が下まで広がってくれません。
今回の実装では複数行になるような長めのTextが入ることが予想されたので、このままではいけません。
どうにかして背景色を下まで広げられないかやってみました。
Table
では実装できず
色々やってみるも結論せっかく便利なTable
クラス。使いこなして必ずや実装を!と意気込みましたが、結局夢叶わずでした笑
Table
をやめ、Column
とRow
で実装してみた(IntrinsicHeight
)
結論IntrinsicHeight
クラスでRow
を囲んでやると綺麗になります!逆にIntrinsicHeight
を使用せず、単にRow
で実装しようとすると、先ほどのTable
で実装したものの二の舞になります...
実装コード => IntrinsicHeight
import 'package:flutter/material.dart';
class IntrinsicHeightScreen extends StatelessWidget {
const IntrinsicHeightScreen({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_customTableRow("会社名", "hogehoge株式会社", isFirst: true),
_customTableRow("住所", "東京都〇〇〇〇"),
_customTableRow("電話番号", "03-××××-××××"),
_customTableRow("沿革", """令和2年4月:hogehoge株式会社設立
令和2年8月:東京に○○店をオープン
令和3年6月:社名を○○へ変更
令和3年5月:売上高1000億円を達成
令和3年12月:マザーズへ株式を上場
"""),
],
),
)),
);
}
Widget _customTableRow(String firstText, String secondText, {bool isFirst = false}) {
return Container(
decoration: (isFirst)
? BoxDecoration(border: Border.all(color: const Color(0XFF000000)))
: const BoxDecoration(
border: Border(
left: BorderSide(color: Color(0XFF000000)),
right: BorderSide(color: Color(0XFF000000)),
bottom: BorderSide(color: Color(0XFF000000)),
),
),
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 1,
child: ColoredBox(
color: const Color(0XFFD3D3D3),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 10.0),
child: Text(firstText),
),
),
),
const VerticalDivider(color: Color(0XFF000000), width: 1),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 10.0),
child: Text(secondText),
),
)
],
),
),
);
}
}
スクリーンショット => IntrinsicHeightで実装
おわりに
今回のいろいろ調べてみて初めてIntrinsicHeight
というクラスを知りました。調べてもなかなか出てこず困ったので、誰かの助けになれば幸いです。
もし他の方法で
- こっちの方がコストが安いよ!
- Tableクラスでもこうすれば実装できるよ!
という方がいらっしゃれば是非ご教授ください!!!
Discussion
はじめまして。
僕も同様の内容で困ったのですが、 こちらでやるとうまくいきました。
少し古いので解決済みでしたらすみません。