0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter】ListView.Builder内のonTapイベントが勝手に呼ばれて困った話

Last updated at Posted at 2024-07-11

何が起きたか

タイトルのままですが。

詳細は省きますが、ListViewの中に動的に画像を表示し、その画像をタップするとカルーセル表示する・・・みたいな処理を実装していました。Twitter(現X)とかでありそうなやつです。

class SampleListBuilder extends StatelessWidget {
  const SampleListBuilder({super.key});

  @override
  Widget build(BuildContext context) {
    final List<String> imageUrlList = ['url1', 'url2', 'url3'];

    return ListView.builder(
      physics: const AlwaysScrollableScrollPhysics(),
      itemCount: imageUrlList.length,
      itemBuilder: (BuildContext context, int index) {
        return Container(
          child: InkWell(
            onTap: _pushCarousel(index),
            child: Image.network(imageUrlList[index], fit: BoxFit.cover,),
          ),
        );
      },
    );
  }

  pushCarousel(context) {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => CarouselView()),
    );
  }
}

ビルドすると以下のエラーが発生します。

'!_debugLocked': is not true.

調査

調べてみると、Widgetのビルド中に画面遷移を行おうとしたりすると発生するエラーとのこと。
全く自覚なし。だってタップしたときのイベントで設定しているんだから。(つもり)

イベントの処理を変えてテストしてみます。

...省略
        return Container(
          child: InkWell(
            onTap: test(index), // テスト用メソッドに変更
            child: Image.network(imageUrlList[index], fit: BoxFit.cover,),
...省略

  test(index) {
    debugPrint('on tap! ' + index.toString());
  }
}

これで一応ビルドは出来るようになりましたが、ビルドしただけなのにコンソールにタップされたよ!のログが並びます。

解決

結論、書き方が悪かったです。
onTap: メソッド(),だとメソッドの戻り値をonTapイベントにセットするような動きをするのだそうです。

onTap: () => test(index),

とするのが正解でした。

または、画面遷移したいのであればちゃんとメソッドに型を指定すれば"void型は設定できないよ"と教えてくれるので気づけたかもしれません。
うーん、不幸が重なった感じ・・・
調べても全然出てこなかったのはあまりに常識的過ぎてこんなミスをする人がいなかったからなのでしょうか。
誰かの助けになれば幸いです。

修正後サンプル

class SampleListBuilder extends StatelessWidget {
  const SampleListBuilder({super.key});

  @override
  Widget build(BuildContext context) {
    final List<String> imageUrlList = ['url1', 'url2', 'url3'];

    return ListView.builder(
      physics: const AlwaysScrollableScrollPhysics(),
      itemCount: imageUrlList.length,
      itemBuilder: (BuildContext context, int index) {
        return Container(
          child: InkWell(
            // ①ラムダ式を使う
            onTap: () => _pushCarousel(index),
            child: Image.network(imageUrlList[index], fit: BoxFit.cover,),
          ),
        );
      },
    );
  }

  // ②返却型は書いたほうが自分のためになる
  void pushCarousel(context) {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => CarouselView()),
    );
  }
}
0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?