Flutter - 小部件的状态没有改变

Posted

技术标签:

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

我几乎是Flutter 的新手,正在尝试开发一个聊天应用程序。每当用户发送消息时,它应该更改WidgetState,并且消息应该显示在Listview 中。 情况是Widget StateButton 按下时不会改变。但是,如果我 Hot Reload 我的应用程序会更改 StateWidget 并显示消息。我为视图使用了两个Widgets,并在Child Widget 中调用了setState() 方法。如何从Child Widget 刷新WidgetState。 请查看我的代码并告诉我解决方案。提前致谢。

父小部件:

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

【问题讨论】:

你可以阅读这个。 flutter.dev/docs/development/data-and-backend/state-mgmt/simple @Darish 我的情况和你建议的文件不一样。 您需要的解决方案是某种状态管理设置,在该文档中,它清楚地解释了如何设置。 setState 仅适用于此特定 Widget 的状态。您不能 setState 并将更改应用到 MyClass @kuhnroyal 我正在尝试设置ChatScreen 的状态。 【参考方案1】:

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

    将您的_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);
      
      ...
    
    

    直接从您的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 更接近于其他可以说更好的状态管理方法,但两者都是直接从子小部件更新父小部件状态的示例。

【讨论】:

感谢您的解释和帮助。我还没有尝试过你的解决方案。我会尝试它,如果它有效,我会投票给它作为正确的解决方案。再次非常感谢。

以上是关于Flutter - 小部件的状态没有改变的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Bloc 不断重建小部件而不改变状态

Flutter:有状态的小部件不更新

Flutter 中的有状态和无状态小部件之间的关系是啥?

如何从另一个小部件类更新小部件树 - Flutter

Flutter:何时创建无状态或有状态页面?

Flutter Bloc 状态管理