-
Notifications
You must be signed in to change notification settings - Fork 0
A Simple Example: Single Form Widget with A Stream
ℹ️ You can see the full implementation of
StreamingSwitch
and more here.
Let's make a switch widget that responds to the changes in real time using streams. In order to do this, we need StreamingSwitch
and StreamController
. StreamController
is already in the built-in Dark SDK.
ℹ️ The name of every streaming form widget starts with
Streaming*
.
⚠️ EveryStreaming*
form widget requires you to useStreamController
.
Let's assume we have a page as below:
class MySwitchPage extends StatelessWidget {
const MySwitchPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
const Text('Switch value is not yet known.'), // we will update this text in realtime
Switch( // this is just a regular built-in switch, we will change this
value: true,
onChanged: (val) {},
),
],
),
),
);
}
}
First, we need to change this into a StatefulWidget
.
class MySwitchPage extends StatefulWidget {
const MySwitchPage({super.key});
@override
State<MySwitchPage> createState() => _MySwitchPageState();
}
class _MySwitchPageState extends State<MySwitchPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
const Text('Switch value is not yet known.'),
Switch(
value: true,
onChanged: (val) {},
),
],
),
),
);
}
}
In _MySwitchPageState
, we will initialize and properly dispose a StreamController<bool>
.
class _MySwitchPageState extends State<MySwitchPage> {
// here we initialize our StreamController
final StreamController<bool> _controller = StreamController();
@override
void dispose() {
// here we need to properly close it so it doesn't leak resources
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
const Text('Switch value is not yet known.'),
Switch(
value: true,
onChanged: (val) {},
),
],
),
),
);
}
}
⚠️ If you'd like to listen toStreamController
in multiple locations in codebase, useStreamController.broadcast()
to initialize it.
And we will use StreamingSwitch
and attach our StreamController
to it:
class _MySwitchPageState extends State<MySwitchPage> {
final StreamController<bool> _controller = StreamController();
@override
void dispose() {
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
const Text('Switch value is not yet known.'),
// here is the StreamingSwitch
StreamingSwitch(
controller: _controller,
// initialValue: true,
),
],
),
),
);
}
}
Finally, we will replace Text
with a StreamBuilder
, which will listen to StreamController
's stream and react on changes.
class _MySwitchPageState extends State<MySwitchPage> {
final StreamController<bool> _controller = StreamController();
@override
void dispose() {
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
// replace text with `StreamBuilder` and listen to controller's stream
StreamBuilder(
stream: _controller.stream,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return const Text('There is no stream yet.');
case ConnectionState.waiting:
return const Text('Waiting for stream connection...');
case ConnectionState.active:
return Text('Switch data: ${snapshot.data}');
case ConnectionState.done:
return const Text('Stream is completed.');
}
},
),
StreamingSwitch(
controller: _controller,
// initialValue: true,
),
],
),
),
);
}
}