I used the Material switch widget for the first time in one of my projects and I initially found it quite tricky to use. After creating the switch widget, I wanted to change its state based on the values I received from Firestore. However, calling setState after retrieving the data did not seem to work.
Initial Code
class SwitchExample extends StatefulWidget {
@override
_SwitchExampleState createState() => _SwitchExampleState();
}
class _SwitchExampleState extends State<SwitchExample> {
bool isSwitch = false;
@override
Widget build(BuildContext context) {
handleSwitch(bool value) {
setState(() {
isSwitch = value;
});
}
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('users').snapshots(),
builder: (context, snapshot) {
if (snapshot.data.active == true) {
setState(() {
isSwitch = true;
});
}
return Scaffold(
body: Center(
child: Switch(
value: isSwitch,
onChanged: (val) {
handleSwitch(val);
},
activeTrackColor: Colors.green,
activeColor: Colors.white,
inactiveTrackColor: Colors.grey,
),
),
);
});
}
}
Thankfully, I was able to find a solution, but before I tell you what it is, here is something you should know about the switch widget.
The switch widget maintains no state of its own
The switch itself does not maintain any state. Instead, when the state of the switch changes, the widget calls the onChanged callback. Most widgets that use a switch will listen for the onChanged callback and rebuild the switch with a new value to update the visual appearance of the switch.
The lines below are the most important in the whole paragraph.
Most Widgets that use a switch will listen for the Onchanged callback and rebuild the switch with a new value to update the visual appearance of the switch
It simply means, widgets will only listen to the onchange callback and update the switch accordingly, and herein lies the problem in the initial code.
The widget cannot listen to
setState(() {
isSwitch = true;
});
because it is not being called from the onchange callback. How then do you change the state dynamically? Here’s a quick solution I was able to come up with below.
Final code
class SwitchExample extends StatefulWidget {
@override
_SwitchExampleState createState() => _SwitchExampleState();
}
class _SwitchExampleState extends State<SwitchExample> {
bool isSwitch = false;
bool dynamicSwitch;
@override
Widget build(BuildContext context) {
handleSwitch(bool value) {
setState(() {
isSwitch = value;
dynamicSwitch = value;
});
}
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('users').snapshots(),
builder: (context, snapshot) {
dynamicSwitch = snapshot.data.active;
return Scaffold(
body: Center(
child: Switch(
value: dynamicSwitch != true ? isSwitch : dynamicSwitch,
onChanged: (val) {
handleSwitch(val);
},
activeTrackColor: Colors.green,
activeColor: Colors.white,
inactiveTrackColor: Colors.grey,
),
),
);
});
}
}
}
So now depending on the value you have in your collection, your switch will change accordingly.
To test out this code, you can create a collection called users on firebase with a document. In the document, create a field (‘active) and set its value to true or false.
I hope you enjoyed this article and thanks for reading till the end.
Top comments (1)
.active is not working