LoginSignup
8
2

More than 3 years have passed since last update.

FlutterのListTileで高さを指定するとレイアウトが崩れる問題

Last updated at Posted at 2020-09-11

背景

現在、業務で一ヶ月半ほどFlutterを使っています。

とても良いチームで、最近はFlutter自体にも夢中になってきました。そんな中、自分の中でListTileに関して疑問が生まれつつあるので、記事を作成することにしました。

ListTileとは

title、subtitle、leading、trailingなどを設定するだけで定番のレイアウトのリストアイテムが作成出来るものです。

スクリーンショット 2020-09-12 0.06.31.png

list_screen.dart

class ListScreen extends StatelessWidget {

  final items = [
    'アイテム1',
    'アイテム2',
    'アイテム3',
    'アイテム4',
    'アイテム5',
    'アイテム6',
    'アイテム7',
    'アイテム8',
    'アイテム9',
    'アイテム10',
    'アイテム11',
    'アイテム12',
    'アイテム13',
    'アイテム14',
    'アイテム15',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListTile Sample'),
      ),
      body: ListView.separated(
        itemCount: items.length,
        itemBuilder: (context, int position) {
          return ListTile(
            title: Text(items[position]),
            subtitle: Text('サブタイトル'),
            leading: Icon(Icons.folder),
            trailing: Icon(Icons.more_vert),
          );
        },
        separatorBuilder: (context, _) => const Divider(),
      ),
    );
  }
}

上のスクショのようなレイアウトがこのように、少ないコードで作成出来る、控えめに言って最高です。

直面した問題

特に業務でレイアウトを作成する場合には、リストの高さが決まっていることが多いと思います。
仮に今回はSizedBoxを使用して、heightを50に指定します。(ここから間違っていたりするのだろうか。。)


itemBuilder: (context, int position) {
          return SizedBox(
            height: 50,
            child: ListTile(
              title: Text(items[position]),
              subtitle: Text('サブタイトル'),
              leading: Icon(Icons.folder),
              trailing: Icon(Icons.more_vert),
            ),
          );
        },

そうするとリストのアイテムが、下記のスクショのように上に空白が出来てコンテンツが下にズレてしまいます。

スクリーンショット 2020-09-12 0.19.01.png

例えば、trailingのアイコンをButtonIconなどにすると、タップのエフェクトがはみ出したりします。

スクリーンショット 2020-09-12 0.40.21.png

ListTileを使用した場合の解決策

これをListTileを使用したまま回避するためには、subtitleのTextの下にPaddingを付けたりなど、かなり無理やりな解決しか発見出来ていません。。

// 苦肉の策
subtitle: Padding(
  padding: const EdgeInsets.only(bottom:20),
    child: Text('サブタイトル'),
),

解決策(とりあえず)

ListTileを使った状態では高さを指定したり細かいレイアウトの調整が上手く出来ませんでした。いったん私の解決策としては、

  • ListTileを使わない

という方法しか現在発見出来ていません。今回のレイアウトをListTileを使わず、高さ50のリストアイテムを実装するとすると以下のようになるでしょうか。(細かいところは異なりますが)


@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListTile Sample'),
      ),
      body: ListView.separated(
        itemCount: items.length,
        itemBuilder: (context, int position) {
          return SizedBox(
            height: 50,
            child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 20),
              child: Row(
                children: [
                  Icon(Icons.folder),
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.only(left: 30),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(items[position]),
                          Text('サブタイトル'),
                        ],
                      ),
                    ),
                  ),
                  Icon(Icons.more_vert)
                ],
              ),
            ),
          );
        },
      ),
    );
  }

スクリーンショット 2020-09-12 1.04.32.png

最近は後からレイアウトの微調整などで困るくらいなら、最初からListTile使わないようにしようかと考えたりしています。
とはいえ、本当はListTileでもしっかりレイアウト作成出来るのでは?とモヤモヤしています。。

ListTileでも良い方法があれば、ご教授お願い出来ますとありがたいです。

[追記]
ありがたいコメント頂きました。
ListTileの公式のドキュメントに以下のような記述があるとのことを教えて頂きました。

A single fixed-height row that typically contains some text as well as a leading or trailing icon.

やはり自分で高さを指定して使うものでは無さそうですね。

8
2
3

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
8
2