I am making an example to understand how it works and the correct use of InheritedWidget
, which until now seems to be misused.
While running the example, reading the documentation, and testing, I notice some issues that I don't understand.
problem 1
Using the example of the documentation on InheritedWidget
, they tell us how it works , how to create it and how to use it , all this with an example of Color
. But they never tell us how I can change that value of Color
.
Example from the documentation :
class FrogColor extends InheritedWidget {
const FrogColor({
Key? key,
required this.color,
required Widget child,
}) : super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
final FrogColor? result = context.dependOnInheritedWidgetOfExactType<FrogColor>();
assert(result != null, 'No FrogColor found in context');
return result!;
}
@override
bool updateShouldNotify(FrogColor old) => color != old.color;
}
After some research and looking at several examples, I managed to do the color change by creating a class ColorBloc
and using Stream
, I use this in my example below when I tackle problem 2
class ColorBloc
class ColorBloc {
Color myColor;
ColorBloc({this.myColor = Colors.amber});
final _color = StreamController<Color>();
Stream<Color> get colorStream => _color.stream;
void changeColor(Color newColor) {
_color.add(newColor);
myColor = newColor;
}
}
problem 2
When using my own InheritedWidget
I realize that apart from using a listener (such as StreamBuilder
) that checks the changes made to the colorBloc
.
If you want to use it on a second screen/route, you need to use MaterialApp
it otherwise when navigating to it it sends the following error.
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building SecondPage(dirty):
The getter 'colorBloc' was called on null.
Receiver: null
Tried calling: colorBloc
The only way I can get it to work correctly is with MaterialApp
, which I don't know if it's the right thing to do since it's not the main of the app and I hope it's a good use of theInheritedWidget
usage exampleInheritedWidget
Home and FirstPage
class MyInheritedWidgetPage extends StatelessWidget {
final myColor = ColorBloc();
@override
Widget build(BuildContext context) {
myColor.myColor = Colors.blue;
return MyInheritedWidget(
colorBloc: myColor,
child: StreamBuilder<Color>(
stream: myColor.colorStream,
builder: (context, snapshot) {
print('myColor => $myColor');
return MaterialApp(
home: FirstPage(),
);
}),
);
}
}
class FirstPage extends StatelessWidget {
const FirstPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final color = MyInheritedWidget.of(context).colorBloc;
return Scaffold(
appBar: AppBar(
title: Text('MyInheritedWidget'),
backgroundColor: color.myColor,
),
body: Center(
child: Column(
children: [
Text('Color nuevo',
style: TextStyle(
color: MyInheritedWidget.of(context).colorBloc.myColor)),
RaisedButton(
child: Text('Set color red'),
onPressed: () {
MyInheritedWidget.of(context).colorBloc.changeColor(Colors.red);
}),
RaisedButton(
child: Text('navigate to second page'),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (_) => SecondPage()));
}),
],
),
),
);
}
}
Second Page
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final color = MyInheritedWidget.of(context).colorBloc;
return Scaffold(
appBar: AppBar(
title: Text('Second'),
backgroundColor: color.myColor,
),
body: Center(
child: Column(
children: [
Text('Hola Mundo', style: TextStyle(color: color.myColor),),
RaisedButton(
child: Text('Change color to amber'),
onPressed: () => color.changeColor(Colors.amber))
],
),
),
);
}
}
All this is my public repository , which I use for small flutter examples