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 ?
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.