Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter GestureDetector, onTap gets triggered automatically, how to?

I have a stateful widget that has a simple grid and each grid cell has a container inside it.

I would like to click on a cell / container and have its content changed.

The problem is that the GestureDetector -> onTap method gets triggered on app refresh for all cels.

In the example below, the _changeCell method gets triggered instantly for all cels and onTap doesn't work.

Any ideas?

import 'package:flutter/material.dart';

class GridWidget extends StatefulWidget {
  @override
  _GridWidgetState createState() => new _GridWidgetState();
}

class _GridWidgetState extends State<GridWidget> {
  @override
  Widget build(BuildContext context) {

    Color cellColor = Colors.white;
    Text cellText = new Text('');

    // when a cell is tapped, change the color and text
    _changeCell(index) {
      setState(() {
        cellColor = Colors.lightBlue;
        cellText = new Text('clicked');
      });
      print("Container clicked " + index.toString());
    }

    // create a 5 by 5 grid 
    return new GridView.count(
      crossAxisCount: 5,
      children: new List.generate(5, (index) {
        return new GestureDetector(
          onTap: _changeCell(index),
          child: new Container(
            width: double.infinity,
            height: double.infinity,
            decoration: new BoxDecoration(
              color: cellColor,
            ),
            child: new Center(
              child: cellText,
            ),
          ),
        );
      }),
    );
  }
}
like image 305
Patrioticcow Avatar asked Apr 26 '18 18:04

Patrioticcow


3 Answers

just change onTap: _changeCell(index) to onTap: () => _changeCell(index) . _changeCell(index) this returns null and you setting null to onTap and calling the same function .

below code is for this

demo2

demo

I played around a little bit.

    import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new DemoScreen(),
  ));
}

class DemoScreen extends StatefulWidget {
  @override
  _DemoScreenState createState() => new _DemoScreenState();
}

class _DemoScreenState extends State<DemoScreen> {
  Color cellColor = Colors.white;

  Text _getText(index) {
    Text text;
    switch (index) {
      case 0:
        text = new Text('lightBlue');
        break;
      case 1:
        text = new Text('red');
        break;
      case 2:
        text = new Text('green');
        break;
      case 3:
        text = new Text('yellow');
        break;
      case 4:
        text = new Text('orange');
        break;
      default:
        text = new Text('brown');
        break;
    }

    return text;
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Demo App"),
      ),
      body: new GridView.count(
        crossAxisCount: 5,
        children: new List.generate(5, (index) {
          return new MyWidget(
            index: index,
            color: cellColor,
            text: _getText(index),
          );
        }),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  final Color color;
  final Text text;
  final int index;

  MyWidget({this.color, this.text, this.index});

  @override
  _MyWidgetState createState() => new _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  Color cellColor = Colors.white;
  Text cellText = new Text('white');

  @override
  void initState() {
    super.initState();
    cellColor = widget.color;
    cellText = widget.text;
  }

  _changeCell(index) {
    setState(() {
      switch (index) {
        case 0:
          cellColor = Colors.lightBlue;
          cellText = new Text('lightBlue');
          break;
        case 1:
          cellColor = Colors.red;
          cellText = new Text('red');
          break;
        case 2:
          cellColor = Colors.green;
          cellText = new Text('green');
          break;
        case 3:
          cellColor = Colors.yellow;
          cellText = new Text('yellow');
          break;
        case 4:
          cellColor = Colors.orange;
          cellText = new Text('orange');
          break;
        default:
          cellColor = Colors.brown;
          cellText = new Text('brown');
          break;
      }
    });
    print("Container clicked " + index.toString());
  }

  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: () => _changeCell(widget.index),
      child: new Container(
        margin: new EdgeInsets.symmetric(horizontal: 1.0),
        width: double.infinity,
        height: double.infinity,
        decoration: new BoxDecoration(
          color: cellColor,
        ),
        child: new Center(
          child: cellText,
        ),
      ),
    );
  }
}

Hope it helps :)

like image 189
Ajay Kumar Avatar answered Oct 25 '22 11:10

Ajay Kumar


There's a problem in your code at this line:

onTap: _changeCell(index),

Basically, instead of setting onTap to a method, you're calling the method directly and setting onTap to the result of that call (null). Each time the widget builds, it will call the function.

What you should be doing is this:

onTap: () => _changeCell(index)
like image 30
rmtmckenzie Avatar answered Oct 25 '22 13:10

rmtmckenzie


TLDR answer for those looking for a quick fix.

Change:

onTap: () => myMethod,

To this:

 onTap: (){ myMethod();},
like image 40
Petro Avatar answered Oct 25 '22 12:10

Petro