Search code examples
flutterflutter-blocflutter-widget

Flutter : my custom Switch widget does not respond to state change


I made a custom SwitchTile widget to avoid code duplication, which is based on a StatefulWidget with a boolean value so this is quiet simple :

class SwitchTile extends StatefulWidget
{
    final String title;
    final bool value;
    final ValueChanged<bool> onChanged;
    
    const SwitchTile({Key? key, required this.title, required this.value, required this.onChanged}) : super(key: key);

    @override
    State<StatefulWidget> createState() => _SwitchTileState();
}

class _SwitchTileState extends State<SwitchTile>
{
    late bool value;
    
    @override
    void initState() 
    {
        super.initState();
        this.value = widget.value;
    }
    
    @override
    Widget build(BuildContext context)
    {
        return ListTile(
            title: Text(widget.title),
            trailing: Switch.adaptive(
                value: this.value,
                onChanged: (newValue) {
                    widget.onChanged(newValue);
                    this.setState(() => this.value = newValue);
                }
            )
        );
    }
    
    @override
    void dispose()
    {
        super.dispose();
    }
}

Now I want to synchronize some SwitchTile widget with another boolean value, but when the value changes it does not rebuild as I expected. I use flutter_bloc, the bloc/events/states work very well. See what I tried to do :

// See my Widget build() method ; bloc variable is declared above
BlocBuilder<ChadsVascBloc, ChadsVascState>(
    builder: (BuildContext context, ChadsVascState state)
    {
        return Column(
            children: [
                // this works very well
                ListTile(
                    title: Text("Switch : ageOver65 is ${state.ageOver65.toString()}"),
                    trailing: Switch.adaptive(
                        value: state.ageOver65,
                        onChanged: (value) => bloc.add(AgeOver65Toggled(ageOver65: value))
                    )
                ),
                // this is does not
                SwitchTile(
                    // the change is well triggered in the title property !!!
                    title: "SwitchTile : ageOver65 is ${state.ageOver65.toString()}",
                    value: state.ageOver65, // but this does not change the button's status
                    onChanged: (value) => bloc.add(AgeOver65Toggled(ageOver65: value))
                )
            ]
        );
    }
),

SwitchTile(
    title: AppLocalizations.of(context)!.ageOver65,
    value: bloc.state.ageOver65,
    onChanged: (value) => bloc.add(AgeOver65Toggled(ageOver65: value)),
)

When I push the last button, the first one work very well ("base" Switch widget) but the second one (custom SwitchTile widget) does not : the title changes but not the button's position.

What did I do wrong ?


Solution

  • Solved : my error was not using BLoC but with bad state management structure. As a Switch widget does not have to manage its own state, my custom Switch widget should not try to changes its own state.

    So it can be a simple StatelessWidget but used inside a parent StatefulWidget, or - I my case - in a BlocBuilder. I finally use a simple context.watch() as the value of my custom widget.