Flutter ListTileでIconをタップした時だけイベントを発生させる

June 02, 2019

codelabs の「Write Your First Flutter App, part 2」ではタップを ListTile 全体で取得していますが、Tile 全体のタップではなく Icon のタップだけを認識するようにします。
codelabs.developers.google.com

20190603005123

結論

IconButtonを使う。

問題

codelabs のサンプルアプリでは、タップイベントをonTapで取得しています。

onTapは ListTile へ結びついているため、Tile のどこをタップしてもハートの色が変化します。

これだと Tile 内でタップイベントを分けたい場合は困ります。

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: Icon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),
    onTap: () {
      setState(() {
        if (alreadySaved) {
          _saved.remove(pair);
        } else {
          _saved.add(pair);
        }
      });
    },
  );
}

解決策

trailingに表示するものをIconではなくIconButtonにすることで簡単に解決できます。

具体的にはtrailingIconButtonを指定し、IconButtonの中でIconとタップイベント取得用のonPressedを記載します。

  Widget _buildRow(WordPair pair) {
    final bool alreadySaved = _saved.contains(pair);
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),

      trailing: IconButton(
        icon: Icon(alreadySaved ? Icons.favorite : Icons.favorite_border,
            color: alreadySaved ? Colors.red : null),
        onPressed: () {
          setState(() {
            if (alreadySaved) {
              _saved.remove(pair);
            } else {
              _saved.add(pair);
            }
          });
        },
      ),
    );
  }

シンプルに、アイコンをボタンにすればいいよねってことです。

試せていませんが Container でウィジェットを分けてからクリックリスナーを付けることもできると思います。

参考

ListTile についてはこのページがわかりやすいです。
ListTile class - material library - Dart API


Profile picture

Twitter GitHub