Reputation: 740
I'm trying to set a StatefulBuilder
widget state outside of its widget. Most examples and the documentation available show the setState
method being used inside the widget, however I'm wondering if such method can be called from outside of the StatefulBuilder
widget. Here's an example:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'StackOverflow Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'StackOverflow Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return new GestureDetector(
//Change one of the icon's color using the tap down function
onTapDown: (TapDownDetails details) {
return changeColor(details);
},
child: Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Center(
child: Column(children: [
//This widget should be rebuilt
StatefulBuilder(
builder: (BuildContext context, StateSetter setState)
{
Color _iconColor = Colors.black;
return Icon(
Icons.money,
size: 50,
color: _iconColor,
);
}
),
//This icon should not be rebuilt
Icon(
Icons.euro,
size: 50,
color: Colors.black,
),
]),
),
),
);
}
void changeColor(TapDownDetails details) {
//Rebuilt StatefulBuilder widget here, but how?
setState(() {
_iconColor = Colors.green;
});
}
}
Currently I get an error because of the _iconColor
variable being used in setState
. I am also aware that it may be impossible to access it outside of the widget. If that's the case, what would be a better solution to change the icon's color without resorting to rebuilding the whole StatefulWidget
?
Thanks for your time.
Upvotes: 3
Views: 3928
Reputation: 6405
This is one way to achieve what you intend, if you have to definitely use the StatefulBuilder
.
Basically we are storing the StateSetter
that we receive from the StatefulBuilder.builder
class Sample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return SampleState();
}
}
class SampleState extends State<Sample> {
StateSetter internalSetter;
Color color = Colors.black;
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: Text('Sample')),
body: Column(
children: [
GestureDetector(
onTap: () {
setState(() {
color = Colors.deepOrange;
});
},
child: Text('Press'),
),
StatefulBuilder(builder: (context, setter) {
internalSetter = setter;
return Container(
height: 100,
width: 100,
color: color,
);
}),
Undisturbed(),
],
),
);
}
}
class Undisturbed extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Undisturbed is built");
return Container(
width: 100,
height: 100,
color: Colors.red,
);
}
}
Upvotes: 1
Reputation: 4569
You can use the ValueListenableBuilder
widget.
Example:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'StackOverflow Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'StackOverflow Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ValueNotifier _iconColor = ValueNotifier<Color>(Colors.black);
@override
Widget build(BuildContext context) {
return new GestureDetector(
//Change one of the icon's color using the tap down function
onTapDown: (TapDownDetails details) {
return changeColor(details);
},
child: Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Center(
child: Column(children: [
//This widget should be rebuilt
ValueListenableBuilder(
valueListenable: _iconColor,
builder: (ctx, value, child) {
return Icon(
Icons.money,
size: 50,
color: value,
);
}
),
//This icon should not be rebuilt
Icon(
Icons.euro,
size: 50,
color: Colors.black,
),
]),
),
),
);
}
void changeColor(TapDownDetails details) =>
_iconColor.value = Colors.green
}
Upvotes: 9