How to use Function callback if i'm use to change state with new val on Switch widget?

Viewed 365

i tried to change new state with Switch widget but it can't be used, in case i create dynamic function and will to used in widget tree's, in function i send callback function at parameter for Switch widget, but in actual it is cannot be used.

code base

import 'package:flutter/material.dart';
import 'package:navigate_app/widgets/main_drawer.dart';

class FilterScreen extends StatefulWidget {
  static const routeNamed = '/filter';

  @override
  State<FilterScreen> createState() => _FilterScreenState();
}

class _FilterScreenState extends State<FilterScreen> {
  bool _glutenFree = false;
  bool _vegetarian = false;
  bool _vegan = false;
  bool _lactoseFree = false;

  Widget _buildSwitchFilter(String title, String description, bool currentValue,
      Function updateValue) {
    return SwitchListTile(
        title: Text(title),
        subtitle: Text(description),
        value: currentValue,
        onChanged: (val) => updateValue);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        drawer: MainDrawer(),
        appBar: AppBar(),
        body: Column(
          children: [
            Expanded(
                child: ListView(
              children: [
                _buildSwitchFilter('Gluten-free',
                    'Only include gluten-free meals', _glutenFree, (newVal) {
                  setState(() {
                    _glutenFree == newVal;
                  });
                }),
                _buildSwitchFilter(
                    'Lactose-free',
                    'Only include lactose-free meals',
                    _glutenFree,
                    (newVal) => _lactoseFree == newVal),
                _buildSwitchFilter(
                    'Vegan-free',
                    'Only include vegan-free meals',
                    _glutenFree,
                    (newVal) => _vegan == newVal),
                _buildSwitchFilter(
                    'Vegetarian-free',
                    'Only include vegetarian-free meals',
                    _glutenFree,
                    (newVal) => _vegetarian == newVal),
              ],
            ))
          ],
        ));
  }
}

it's pict

6 Answers

There are several reasons why this isn't working:

  1. Not actually invoking your callback or passing the value:
    Widget _buildSwitchFilter(
      String title,
      String description, 
      bool currentValue,
      Function updateValue,
    ) {
    return SwitchListTile(
        title: Text(title),
        subtitle: Text(description),
        value: currentValue,
        onChanged: (val) => updateValue);
    }

Should instead be:

    Widget _buildSwitchFilter(
      String title,
      String description, 
      bool currentValue,
      Function(bool value) updateValue, // <- note the return value
    ) {
    return SwitchListTile(
        title: Text(title),
        subtitle: Text(description),
        value: currentValue,
        onChanged: (val) => updateValue(val)); // <- passing the `val` to your callback
    }
  1. Copypasta'd ListView children. Each _buildSwitchFilter() should have the related state value as to what they're for, but each uses _glutenFree as their state value.

  2. 3 out of 4 switches aren't calling setState() when their callback is triggered.

  3. You're not updating local state values, you're comparing equality.

setState(() {
  _glutenFree == newVal;
});

Should be:

setState(() {
  _glutenFree = newVal;
});

== is a method operator

basically is an equality operator. The default behavior for all Objects is to return true if and only if this and others are the same object. Override this method to specify a different equality relation on a class.

        _buildSwitchFilter('Gluten-free',
            'Only include gluten-free meals', _glutenFree, (newVal) {
          setState(() {
            _glutenFree == newVal;
          });
        }),

basically this line work as conditional operator _glutenFree == newVal;

So, if you want to assign any value to any variable like as you want to assign `_glutenFree = false/true

So, on that condition, you should use the assignment operator "="

like right way is,

  _glutenFree = newVal;
import 'package:flutter/material.dart';
import 'package:navigate_app/widgets/main_drawer.dart';

class FilterScreen extends StatefulWidget {
  static const routeNamed = '/filter';

  @override
  State<FilterScreen> createState() => _FilterScreenState();
}

class _FilterScreenState extends State<FilterScreen> {
  bool _glutenFree = false;
  bool _vegetarian = false;
  bool _vegan = false;
  bool _lactoseFree = false;

  Widget _buildSwitchFilter(String title, String description, bool currentValue,
      Function(bool) updateValue) {
    return SwitchListTile(
        title: Text(title),
        subtitle: Text(description),
        value: currentValue,
        onChanged: (val) => updateValue);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        drawer: MainDrawer(),
        appBar: AppBar(),
        body: Column(
          children: [
            Expanded(
                child: ListView(
              children: [
                _buildSwitchFilter('Gluten-free',
                    'Only include gluten-free meals', _glutenFree, (newVal) {
                  setState(() {
                    _glutenFree = newVal;
                  });
                }),
                _buildSwitchFilter(
                    'Lactose-free',
                    'Only include lactose-free meals',
                    _lactoseFree,
                    (newVal) {
                      setState(() {
                    _lactoseFree = newVal;
                  });
                    } ),
                _buildSwitchFilter(
                    'Vegan-free',
                    'Only include vegan-free meals',
                    _vegan,
                    (newVal)  {
                      setState(() {
                    _vegan = newVal;
                  });
                    } ),
                _buildSwitchFilter(
                    'Vegetarian-free',
                    'Only include vegetarian-free meals',
                    _vegetarian,
                    (newVal) {
                       setState(() {
                    _vegetarian = newVal;
                  });
                    } ),
              ],
            ))
          ],
        ));
  }
}

Here in code are 4 problems:

  1. You need to use "=" operator instead of "==" (_glutenFree = newVal instead of _glutenFree == newVal)

  2. You need to pass to the _buildSwitchFilter() - "Function(bool) updateValue" as an argument, and use "onChanged: updateValue":

    Widget _buildSwitchFilter(String title, String description, bool currentValue,
          Function(bool) updateValue) {
        return SwitchListTile(
           title: Text(title),
           subtitle: Text(description),
           value: currentValue,
           onChanged: updateValue);
      }
    
  3. You passing everywhere _glutenFree as third argument in _buildSwitchFilter(), but you need to pass:

_glutenFree;

_lactoseFree;

_vegan;

_vegetarian;

  1. You pass function with setState(){} only first time, You need to do it in all _buildSwitchFilter().

Here is the solution:

    import 'package:flutter/material.dart';
    import 'package:navigate_app/widgets/main_drawer.dart';
    
    class FilterScreen extends StatefulWidget {
      static const routeNamed = '/filter';
    
      @override
      State<FilterScreen> createState() => _FilterScreenState();
    }
    
    class _FilterScreenState extends State<FilterScreen> {
      bool _glutenFree = false;
      bool _vegetarian = false;
      bool _vegan = false;
      bool _lactoseFree = false;
    
    Widget _buildSwitchFilter(String title, String description, bool currentValue,
          Function(bool) updateValue) {
        return SwitchListTile(
            title: Text(title),
            subtitle: Text(description),
            value: currentValue,
            onChanged: updateValue);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            drawer: MainDrawer(),
            appBar: AppBar(),
            body: Column(
              children: [
                Expanded(
                    child: ListView(
                      children: [
                        _buildSwitchFilter('Gluten-free',
                            'Only include gluten-free meals', _glutenFree, (newVal) {
                              setState(() {
                                _glutenFree = newVal;
                              });
                            }),
                        _buildSwitchFilter(
                            'Lactose-free',
                            'Only include lactose-free meals',
                            _lactoseFree,
                                (newVal) {
                                  setState(() {
                                    _lactoseFree = newVal;
                                  });
                                }),
                        _buildSwitchFilter(
                            'Vegan-free',
                            'Only include vegan-free meals',
                            _vegan,
                                (newVal) {
                              setState(() {
                                _vegan = newVal;
                              });
                            }),
                        _buildSwitchFilter(
                            'Vegetarian-free',
                            'Only include vegetarian-free meals',
                            _vegetarian,
                                (newVal) {
                              setState(() {
                                _vegetarian = newVal;
                              });
                            }),
                      ],
                    ))
              ],
            ));
      }
    }

In addition to these corrections, you need to use the correct boolean variables (_vegetarian, _vegan, _lactoseFree) for each of your _buildSwitchFilter widgets. Also, it should be "vegan", not "vegan-free".

Related