surga Lab

開発したい!!

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

codelabsの「Write Your First Flutter App, part 2」ではタップをListTile全体で取得していますが、

codelabs.developers.google.com

Tile全体のタップではなく、Iconのタップだけを認識するようにします。

f:id:hisurga:20190603005123j:plain:w200

結論

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