SetState 不适用于 listview.builder

Posted

技术标签:

【中文标题】SetState 不适用于 listview.builder【英文标题】:SetState not working with listview.builder 【发布时间】:2021-08-12 04:13:38 【问题描述】:

我这里有一些用于应用程序聊天屏幕的代码。这个特定的聊天屏幕用于与机器人聊天。该机器人应该在用户发送每条消息后发送一条消息。机器人要发送的消息列表存储在 messageStrings 中。我正在使用 listview.builder 来使用列表消息中添加的新消息填充 UI。

我正在使用 setstate 添加新消息,但 UI 未使用新消息进行更新。这是我的代码:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../models/chats.dart';

class ReportPage extends StatefulWidget 
  BuildContext context;
  ReportPage(this.context);
  @override
  _ReportPageState createState() => _ReportPageState();


class _ReportPageState extends State<ReportPage> 
  
  @override
  Widget build(Object context) 
    TextEditingController messageContoller = new TextEditingController();

    //The first two messages by the bot are already added to the List
    List<ChatMessage> messages = [
    ChatMessage(messageContent: "Message 1", messageType: "receiver"),
    ChatMessage(messageContent: "Message 2", messageType: "receiver"),
  ];
  int messageIndex = 0;
  //The next messages that are to be added to the list after a response from the user
  List<String> messageStrings = ["Message 3", "Message 4","Message 5",];
    return Scaffold(
      appBar: AppBar(
        title: Row(children: [
          Container(
            width: 35,
            height: 35,
            child: Image.asset(
              'assets/images/police.png',
              fit: BoxFit.cover,
            ),
            decoration:
                BoxDecoration(shape: BoxShape.circle, color: Colors.white),
          ),
          SizedBox(
            width: 10,
          ),
          Text("CFB bot"),
        ]),
      ),
      body: Container(
        padding: EdgeInsets.all(20),
        child: Stack(
          children: <Widget>[
            ListView.builder(
              itemCount: messages.length,
              shrinkWrap: true,
              padding: EdgeInsets.only(top: 10, bottom: 10),
              physics: NeverScrollableScrollPhysics(),
              itemBuilder: (context, index) 
                return Container(
                  padding:
                      EdgeInsets.only(left: 14, right: 14, top: 10, bottom: 10),
                  child: Align(
                    alignment: (messages[index].messageType == "receiver"
                        ? Alignment.topLeft
                        : Alignment.topRight),
                    child: Container(
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(20),
                        color: (messages[index].messageType == "receiver"
                            ? Colors.grey.shade200
                            : Colors.blue[200]),
                      ),
                      padding: EdgeInsets.all(16),
                      child: Text(
                        messages[index].messageContent,
                        style: TextStyle(fontSize: 15),
                      ),
                    ),
                  ),
                );
              ,
            ),
            Align(
              alignment: Alignment.bottomLeft,
              child: Container(
                decoration: BoxDecoration(
                    border: Border.all(color: Colors.black),
                    borderRadius: BorderRadius.all(Radius.circular(20))),
                padding: EdgeInsets.only(left: 10, bottom: 10, top: 10),
                height: 60,
                width: double.infinity,
                child: Row(
                  children: <Widget>[
                    GestureDetector(
                      onTap: () ,
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                          color: Colors.lightBlue,
                          borderRadius: BorderRadius.circular(30),
                        ),
                        child: Icon(
                          Icons.add,
                          color: Colors.white,
                          size: 20,
                        ),
                      ),
                    ),
                    SizedBox(
                      width: 15,
                    ),
                    Expanded(
                      child: TextField(
                        decoration: InputDecoration(
                            hintText: "Write message...",
                            hintStyle: TextStyle(color: Colors.black54),
                            border: InputBorder.none),
                            controller: messageContoller,
                      ),
                    ),
                    SizedBox(
                      width: 15,
                    ),
                    FloatingActionButton(
                      onPressed: () 
                        String message = messageContoller.text;
                        setState(() 
                          messages.add(ChatMessage(messageContent: message, messageType: "sender"));              
                          messages.add(ChatMessage(messageContent: messageStrings[messageIndex], messageType: "receiver"));                                        
                        );
                        messageIndex++;
                        for(int i = 0; i < messages.length; i++)
                          print(messages[i].messageContent);
                        
                      ,
                      child: Icon(
                        Icons.send,
                        color: Colors.white,
                        size: 18,
                      ),
                      backgroundColor: Colors.blue,
                      elevation: 0,
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  

【问题讨论】:

【参考方案1】:

不要直接使用List.add,而是尝试将messages的引用更改为全新的List,就像这样,

messages = [
    ...messages,
    ChatMessage(messageContent: message, messageType: "sender"),
    ChatMessage(messageContent: messageStrings[messageIndex], messageType: "receiver")
];

为什么这样做是因为现在,您正在销毁 messages 的旧引用并为其分配一个全新的 List 引用。

【讨论】:

感谢您的回答。我试过了,它仍然没有更新 UI。有没有其他方法可以解决这个问题? 这是不可能的。 所以你是说,即使你改变了 setState 中的任何东西,你的 UI 也不会重建? 在您的构建函数中添加print 语句以检查它是否被调用。 对不起伙计,问题是我把列表放在了构建函数中。因此,它每次都被重置。我把它放在 State Class 中,现在它工作正常。感谢您的帮助

以上是关于SetState 不适用于 listview.builder的主要内容,如果未能解决你的问题,请参考以下文章

React setState 不适用于 if 语句

this.setState 不适用于 react-native 中的多个文本输入

getCurrentPosition 中的 React-native-maps setState 不适用于我的 url API

Flutter - 另一个 Listview 中的 Listview.builder

setState() 是不是可用于更新 Alt.js 商店中的状态?

是否应该始终将函数用于传递数组或对象的 setState?