【问题标题】:Flutter - State of widget is not changingFlutter - 小部件的状态没有改变
【发布时间】:2020-05-27 22:47:03
【问题描述】:

我几乎是Flutter 的新手,正在尝试开发一个聊天应用程序。每当用户发送消息时,它应该更改Widget 的State,并且消息应该显示在Listview 中。

情况是Widget State 在Button 按下时不会改变。但是,如果我 Hot Reload 我的应用程序会更改 State 的 Widget 并显示消息。我为视图使用了两个Widgets,并在Child Widget 中调用了setState() 方法。如何从Child Widget 刷新Widget 的State。

请查看我的代码并告诉我解决方案。提前致谢。



父小部件:

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()),
        ],
      ),
    );
  }

}



子小部件:

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 我的情况和你建议的文件不一样。
  • 您需要的解决方案是某种状态管理设置,在该文档中,它清楚地解释了如何设置。
  • setState 仅适用于此特定 Widget 的状态。您不能 setState 并将更改应用到 MyClass。
  • @kuhnroyal 我正在尝试设置ChatScreen 的状态。

标签: flutter dart widget state


【解决方案1】:

首先,@Darish 是正确的,您可能应该使用另一种状态管理系统,但对于“如何从子小部件刷新小部件的状态”这个问题。我将提供两个简单的答案:

  1. 将您的_handleSubmitted 方法移动到您的ChatState 小部件并将其传递给您的ChatWidget:

    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);
        });
      }
    }
    

    然后从您的子小部件:

    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);
      }
      ...
    }
    
  2. 直接从您的ChatWidgetState 访问您的ChatState:

    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);
        });
      }
    }
    

    然后在您的ChatWidget 中您可以保持原样,但在您的ChatWidgetState 中更改您的_handleSubmitted 方法,如下所示:

    void _handleSubmitted(String text) {
      _textController.clear();
    
      ChatScreen.of(context).onMessageSubmitted(text);
    }
    

数字 2 更接近于其他可以说更好的状态管理方法,但两者都是直接从子小部件更新父小部件状态的示例。

【讨论】:

  • 感谢您的解释和帮助。我还没有尝试过你的解决方案。我会尝试它,如果它有效,我会投票给它作为正确的解决方案。再次非常感谢。
猜你喜欢
  • 2021-07-12
  • 2019-09-23
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 2018-09-01
  • 2019-06-10
  • 2020-07-31
  • 2022-01-25
相关资源
最近更新 更多