Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to use a variable parameter in a Flutter callback?

I have a simplified flutter control, think of a row of ‘radio’ buttons or a menu bar. The parent passes in a list of ‘captions’ for each button and a callback. The control then hits the callback passing the index of the button tapped. The issue is, the ‘buttons’ are created dynamically and the quantity may vary by the parent. When I set the callback for the onTap function in GestureDetector, it will always hit the callback with the last value of the parameter (idx) in the loop. So if there are 4 buttons, the doCallback is always called with a 4, no matter which button is tapped. It appears like doCallback is being called with a reference to idx, rather than the value of idx. Is there a way to make each button send it’s own index to the callback?

class CtrlRadioSelector extends StatelessWidget {
  CtrlRadioSelector({Key? key, required this.captions, required this.onTapItem})
      : super(key: key);
  final List<String> captions;
  final ValueSetter<int> onTapItem;

  @override
  Widget build(BuildContext context) {
    List<Widget> selectorItems = [];
    int idx = 0;
    for (var caption in captions) {
      selectorItems.add(Expanded(
          flex: 10,
          child: GestureDetector(
              onTap: () => doCallback(idx),
              child: Text(caption,
                  textAlign: TextAlign.center,
                  style: TextStyle(fontSize: 18)))));
      idx++;
    }
    return Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: selectorItems);
  }

  void doCallback(int idx) {
    onTapItem(idx);
  }
}

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

One fix would be use a for loop that iterates with an index, which you need anyway:

    for (var idx = 0; idx < captions.length; i += 1) {
      selectorItems.add(Expanded(
          flex: 10,
          child: GestureDetector(
              onTap: () => doCallback(idx),
              child: Text(captions[idx],
                  textAlign: TextAlign.center,
                  style: TextStyle(fontSize: 18)))));
    }

This is because Dart specifically makes closures capture a for-loop’s index (and not the values of all in-scope variables). Per the Dart Language Tour:

Closures inside of Dart’s for loops capture the value of the index, avoiding a common pitfall found in JavaScript. For example, consider:

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());

The output is 0 and then 1, as expected. In contrast, the example would print 2 and then 2 in JavaScript.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading