Flutter - State of widget is not changing
Firstly, @Darish is right in that you should probably use another kind of state management system but for the question "How do I refresh the State of the Widget from Child Widget." I'll provide two simple answers:
Move your
_handleSubmitted
method up to yourChatState
widget and pass it through to yourChatWidget
:class ChatState extends State<ChatScreen> { ... @override Widget build(BuildContext context) { ... Container( child: ChatWidget(onMessageSubmitted: this._handleSubmitted)), ... } void _handleSubmitted(String text) { ChatMessage message = new ChatMessage( text: text, ); setState(() { MyClass.messages.insert(0, message); }); } }
Then from your child widget:
class ChatWidget extends StatefulWidget { final Function(String) onMessageSubmitted; ChatWidget({this.onMessageSubmitted}); @override ChatWidgetState createState() => ChatWidgetState(); } class ChatWidgetState extends State<ChatWidget> { ... Widget _buildTextComposer() { ... TextField( controller: _textController, onSubmitted: _handleSubmitted, decoration: InputDecoration.collapsed( hintText: "Send a message"), ), ... IconButton( ... onPressed: () { _handleSubmitted(_textController.text); }, ), ... } void _handleSubmitted(String text) { _textController.clear(); widget.onMessageSubmitted(text); } ... }
Access your
ChatState
directly from yourChatWidgetState
:class ChatScreen extends StatefulWidget { ... static ChatState of(BuildContext context) => context.findAncestorStateOfType<ChatState>(); } class ChatState extends State<ChatScreen> { ... void onMessageSubmitted(String text) { ChatMessage message = new ChatMessage( text: text, ); setState(() { MyClass.messages.insert(0, message); }); } }
Then in your
ChatWidget
you can keep as is, but in yourChatWidgetState
change your_handleSubmitted
method like so:void _handleSubmitted(String text) { _textController.clear(); ChatScreen.of(context).onMessageSubmitted(text); }
Number 2 is closer to other arguably better methods of state management, but both are examples of updating the state of a parent widget directly from a child widget.
Shafiul Islam Sajib
Updated on December 17, 2022Comments
-
Shafiul Islam Sajib over 1 year
I am almost new to
Flutter
and trying to develop a chat application. Whenever the user sends a message it should change theState
of theWidget
and the message should be displayed in aListview
.
The case is that theWidget State
does not change onButton
press. But if IHot Reload
my app it changes theState
of theWidget
and the message is displayed. I am using twoWidgets
for the view and thesetState()
method is called in theChild Widget
. How do I refresh theState
of theWidget
fromChild Widget
.
Please review my codes and let me know the solution for it. Thanks in advance.
Parent Widget:class ChatScreen extends StatefulWidget { @override ChatState createState() => ChatState(); } class ChatState extends State<ChatScreen> { static const int _logout = 303; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(Strings.appNameString), actions: <Widget>[ //IconButton(icon: Icon(Icons.add), onPressed: () {}), PopupMenuButton<int>( icon: Icon(Icons.more_vert), elevation: 10, //padding: EdgeInsets.all(5), offset: Offset(0, 100), itemBuilder: (BuildContext context) => [ PopupMenuItem(child: Text("Logout"), value: _logout,), //PopupMenuDivider(height: 5,), ], onSelected: (value) { switch(value) { case _logout: { MyClass.SignOutofGoogle(); } break; default: break; } }, ), ], ), body: Column( // crossAxisAlignment: CrossAxisAlignment.center, // mainAxisSize: MainAxisSize.max, // mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Flexible(child: ListView.builder( padding: new EdgeInsets.all(8.0), reverse: true, itemBuilder: (_, int index) => MyClass.messages[index], itemCount: MyClass.messages.length)), Container( child: ChatWidget()), ], ), ); } }
Child Widget:class ChatWidget extends StatefulWidget { @override ChatWidgetState createState() => ChatWidgetState(); } class ChatWidgetState extends State<ChatWidget> { final TextEditingController _textController = new TextEditingController(); Widget _buildTextComposer() { return Container( margin: const EdgeInsets.symmetric(horizontal: 10.0), child: Align( child: Column( children: <Widget>[ Divider(height: 5.0, color: Colors.lightBlue,), Container( height: 6.8 * SizeConfig.heightSizeMultiplier, child: Row( children: <Widget>[ Container( child: IconButton( icon: Icon(Icons.add_photo_alternate), iconSize: 6.7 * SizeConfig.imageSizeMultiplier, color: Colors.lightBlueAccent, onPressed: () {}), ), Flexible( child: TextField( controller: _textController, onSubmitted: _handleSubmitted, decoration: InputDecoration.collapsed( hintText: "Send a message"), ), ), Container( margin: EdgeInsets.symmetric(horizontal: 4.0), child: IconButton( icon: Icon(Icons.send), iconSize: 6.7 * SizeConfig.imageSizeMultiplier, color: Colors.lightBlueAccent, onPressed: () { _handleSubmitted(_textController.text); }), ), ], ), ), ], ), ), ); } void _handleSubmitted(String text) { _textController.clear(); ChatMessage message = new ChatMessage( text: text, ); setState(() { MyClass.messages.insert(0, message); }); } @override Widget build(BuildContext context) { return _buildTextComposer(); } } class ChatMessage extends StatelessWidget { final String text; ChatMessage( { this.text }); @override Widget build(BuildContext context) { return new Container( margin: const EdgeInsets.symmetric(vertical: 10.0), child: Row( //crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ Column( crossAxisAlignment: CrossAxisAlignment.end, children: <Widget>[ //Text(MyClass.loggeduser.userName, style: Theme.of(context).textTheme.subhead), Text("Sajib", style: Theme.of(context).textTheme.subhead), Container( margin: const EdgeInsets.only(top: 5.0), child: Text(text), ), ], ), Container( margin: const EdgeInsets.only(right: 6.0, left: 12.0), child: CircleAvatar( //backgroundImage: NetworkImage(MyClass.loggeduser.photoUrl)), child: Icon(Icons.account_circle, color: Colors.lightBlueAccent,)), ), ], ), ); } }
-
Darish over 4 yearsyou may read this. flutter.dev/docs/development/data-and-backend/state-mgmt/simple
-
Shafiul Islam Sajib over 4 years@Darish My case is not the same as in the document suggested by you.
-
Darish over 4 yearsThe solution you need is some kind of state management set up, and in that document, it clearly explains how to setup one.
-
kuhnroyal over 4 years
setState
only works for the state of this particular Widget. You can notsetState
and apply changes toMyClass
. -
Shafiul Islam Sajib over 4 years@kuhnroyal I am trying to setState the state of
ChatScreen
. -
kuhnroyal over 4 yearsYou are calling
setState
inChatWidgetState
but it has not state. Your state (messages) is inMyClass
. As Darish said, you need some form of state management. -
Shafiul Islam Sajib over 4 years@kuhnroyal ok. I will try something based on the documentation. But a proper example would be more helpful for me.
-
-
Shafiul Islam Sajib over 4 yearsThank you for your explanation and help. I haven't tried your solution yet. I will try it and if it works I will vote this as the correct solution. Thanks a lot again.