Flutter ListView刷新问题

做的是文字类对话游戏,需要用循环播放剧本

List messages = []; //消息容器列表

//聊天页面
Column(children: [
            Flexible(
                child: SizeCacheWidget(
                    estimateCount: 60,
                    child: Padding(
                        padding: EdgeInsets.only(
                            top: 40.h, bottom: choose_one.isEmpty ? 0 : 80.h),
                        child: ListView.builder(
                          controller: _scrollController, //绑定控件
                          scrollDirection: Axis.vertical, //垂直滑动
                          reverse: false, //正序显示
                          shrinkWrap: true, //内容适配
                          physics: BouncingScrollPhysics(), //内容超过一屏 上拉有回弹效果
                          itemBuilder: (_, int index) => messages[index],
                          itemCount: messages.length,
                        ))))
          ])
//消息气泡类:中气泡
class MiddleMsg extends StatelessWidget {
  MiddleMsg({required this.text});
  final String text; //消息气泡内文本

  @override
  Widget build(BuildContext context) {
    return Container(
        margin: EdgeInsets.only(top: 10.h), //消息间隔
        child: Row(
            mainAxisAlignment: MainAxisAlignment.center, //水平居中对齐
            children: <Widget>[
              // 消息气泡容器
              Container(
                  padding: EdgeInsets.all(10.r), //容器内边距
                  //圆角
                  decoration: BoxDecoration(
                      color: Color.fromRGBO(38, 38, 38, 1), //容器背景颜色
                      borderRadius:
                          BorderRadius.all(Radius.circular(7))), //圆角角度
                  //消息文本
                  child: Text(
                    text,
                    textAlign: TextAlign.center, 
                    style:
                        TextStyle(fontSize: 20.sp)
                  )),
            ]));
  }
}
//发送中气泡
  sendMiddle(String text)  {
    MiddleMsg message = MiddleMsg(text: text);
    messages.add(message);
    setState(() {});
  }
//模拟播放剧本
List msg = ['对方已上线', '对方已上线', '对方已上线', '对方已上线', '对方已上线'];
  test() {
    do {
      for (var value in msg) {
        sendMiddle(value);
      }
    } while (messages.length < msg.length);
  }

运行,本来我是想发送出来的消息是逐条刷新的(模拟真实聊天),没想到一次刷新出全部来,我该如何修改,试过用Timer和Future.delayed延迟执行,但还是没有达到我想要的效果,加了延迟也还是一次全部刷新出来

img

要实现逐条刷新的效果,可以使用Future的延迟来模拟聊天的时间间隔,以便一条一条地添加消息并更新UI。下面是一个简单的实现示例:

test() async {
  for (var value in msg) {
    sendMiddle(value);
    await Future.delayed(Duration(seconds: 1)); // 模拟聊天间隔为1秒
  }
}

以下答案引用自GPT-3大模型,请合理使用:

实例谢谢

// 你可以尝试使用Future.delayed()函数来实现列表渐变的刷新效果:

List messages = []; //消息容器列表

//聊天页面
Column(children: [
            Flexible(
                child: SizeCacheWidget(
                    estimateCount: 60,
                    child: Padding(
                        padding: EdgeInsets.only(
                            top: 40.h, bottom: choose_one.isEmpty ? 0 : 80.h),
                        child: ListView.builder(
                        controller: _scrollController, //绑定控件
                        scrollDirection: Axis.vertical, //垂直滑动
                        reverse: false, //正序显示
                        shrinkWrap: true, //内容适配
                        physics: BouncingScrollPhysics(), //内容超过一屏 上拉有回弹效果
                        itemBuilder: (_, int index) => messages[index],
                        itemCount: messages.length,
                        ))))
          ])

//消息气泡类:中气泡
class MiddleMsg extends StatelessWidget {
  MiddleMsg({required this.text});
  final String text; //消息气泡内文本

  @override
  Widget build(BuildContext context) {
    return Container(
        margin: EdgeInsets.only(top: 10.h), //消息间隔
        child: Row(
            mainAxisAlignment: MainAxisAlignment.center, //水平居中对齐
            children: <Widget>[
              // 消息气泡容器
              Container(
                  padding: EdgeInsets.all(10.r), //容器内边距
                  //圆角
                  decoration: BoxDecoration(
                      color: Color.fromRGBO(38, 38, 38, 1), //容器背景颜色
                      borderRadius:
                      BorderRadius.all(Radius.circular(7))), //圆角角度
                  //消息文本
                  child: Text(
                    text,
                    textAlign: TextAlign.center, 
                    style:
                        TextStyle(fontSize: 20.sp)
                  )),
            ]));
  }
}

//发送中气泡
  sendMiddle(String text)  {
    MiddleMsg message = MiddleMsg(text: text);
    messages.add(message);
    setState(() {});
  }

//模拟播放剧本
List msg = ['对方已上线', '对方已上线', '对方已上线', '对方已上线', '对方已上线'];
  test() async{
    for (var value in msg) {
      await Future.delayed(Duration(seconds: 1)) //延迟1秒
      sendMiddle(value);
    }
  }

如果我的回答解决了您的问题,请采纳我的回答

你的代码中使用了一个循环将剧本中的消息一次性全部发送出来,因此导致了一次性刷新所有消息的效果。如果想要实现逐条刷新的效果,可以考虑使用异步的方式,每隔一段时间发送一条消息,直到全部消息发送完毕。下面是一种可能的实现方式:

首先定义一个方法 _sendDelayed,用于延迟一段时间后发送消息。这里使用了 Future.delayed 来实现延迟,每次发送消息后等待一段时间再继续发送下一条消息:

Future<void> _sendDelayed(String message, Duration delay) async {
  await Future.delayed(delay);
  sendMiddle(message);
}


然后在 test 方法中,通过 for 循环逐条发送消息。使用 await 等待每条消息发送完成后再发送下一条消息:

test() async {
  messages.clear(); // 清空消息列表
  for (var value in msg) {
    await _sendDelayed(value, const Duration(seconds: 1));
  }
}


注意,这里需要在循环前清空消息列表,以确保每次执行 test 方法都从空白的聊天页面开始。

最后,在需要执行剧本的地方调用 test 方法即可。

如果对您有帮助,请给与采纳,谢谢。

是不是需要使用StatefulWidget而不是statelesswidget