raiton
raiton

Reputation: 121

GestureDetector ontap() gets triggered by build

In my build, I have this function that basically stacks a button and a counter, i'm also passing a function (this let's me reuse the buildbuttoncolumn for all buttons instead of copying code arround

my build:

Widget build(BuildContext context) {
List<Widget> _layouts = [
  _videoInfo(),
  _channelInfo(),
  _comment(),
  _moreInfo(),
  VideoList(
    channel: widget.channel,
    isMiniList: true,
    currentVideoId: widget.detail.id
  ),
];

if (MediaQuery.of(context).orientation == Orientation.landscape) {
  _layouts.clear();
}

return Scaffold(
    body: Column(children: <Widget>[
      _buildVideoPlayer(context),
      Expanded(
        child: ListView(
          children: _layouts,
        ),
      )
    ]));

}

my videoinfo:

Widget _videoInfo() {
return Column(
  children: <Widget>[
    ListTile(
      title: Text(widget.detail.title),
      subtitle: Text(widget.detail.viewCount + ' . ' + widget.detail.publishedTime),
      trailing: Icon(Icons.arrow_drop_down),
    ),
    Container(
      padding: EdgeInsets.all(8.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          _buildButtomColumn(Icons.thumb_up, widget.detail.likeCount, function: _like(widget.detail.id, true)),
          _buildButtomColumn(Icons.thumb_down, widget.detail.dislikeCount, function: _like(widget.detail.id, false)),
          _buildButtomColumn(CupertinoIcons.share_up, "Partilhar"), //function: share(context, widget.detail.player)
          _buildButtomColumn(Icons.add_to_photos, "Guardar"),
        ],
      ),
    )
  ],
);

}

 _buildButtomColumn(Icons.thumb_up, widget.detail.likeCount, function: _like(widget.detail.id, true)),

the method then does something like this:

Widget _buildButtomColumn(IconData icon, String text, {function}) {
return GestureDetector(
    onTap: () => function 
    child: Column(.....

oh and here's the like:

_like(String videoId, bool liked) {
  youtubeAPI.likeDislikeVideo(videoId, liked);
}

when I open the page, the onTap gets triggered without me actually pressing the button.

Upvotes: 5

Views: 1449

Answers (1)

Sergey Salnikov
Sergey Salnikov

Reputation: 1781

Where is the problem?

You are calling that function yourself, there is no problem with onTap callback and it is not fired somehow without user interaction

Next snippet performs _like function invocation and pass returned result to function:... arg (refer to lang tour)

function: _like(widget.detail.id, true)

You can prevent such situations if you declare function: argument type as Function and you will get static analysis type error before you run code

_buildButtomColumn(IconData icon, String text, {Function function})

Back to you code - how to fix it?

  1. pass function argument directly to onTap argument
Widget _buildButtomColumn(IconData icon, String text, {VoidCallback function}) {
/// here I enforced type as VoidCallback - it is typedef for `void Function()`
return GestureDetector(
    onTap: function, // <-- pass function, onTap type is VoidCallback
    child: Column(.....

2.a. pass anonymous function with desired payload

_buildButtomColumn(Icons.thumb_up, widget.detail.likeCount,
   function: () => youtubeAPI.likeDislikeVideo(videoId, liked), // <-- this will be invoked later 
)

2.b. this variant is for sake of completeness

declare callable class and pass it's instance to function:... arg ()

class LikeCommand {
  final String videoId;
  final bool liked;
  LikeCommand(this.videoId, this.liked);
  void call() => youtubeAPI.likeDislikeVideo(videoId, liked);
}

_buildButtomColumn(Icons.thumb_up, widget.detail.likeCount,
   function: LikeCommand(videoId, liked),
)

PS I recommend declaring types, since dart is a strongly typed language and specifying types will save you from typical problems in the future

PPS feel free to reach me in comments

Upvotes: 4

Related Questions