Flutter调用OpenAI API二次请求UI无更新问题求助
修复Flutter OpenAI应用第二次请求UI不更新的问题
问题根源
- AnimatedTextKit未设置唯一Key:第二次请求替换
chatList后,ListView.builder会复用之前的AnimatedTextKit实例,而该实例的动画已完成(totalRepeatCount:1),不会重新渲染新内容。 - 聊天列表直接替换而非追加:每次请求直接覆盖
chatList,既不符合聊天逻辑,也容易触发Widget复用导致UI不更新。
修复步骤
1. 给AnimatedTextKit添加唯一Key
在ListView的itemBuilder中,为AnimatedTextKit设置基于内容的唯一Key,确保内容更新时Widget会强制重建:
itemBuilder: (context, index) { return AnimatedTextKit( key: ValueKey(chatList[index].message!.content), // 用消息内容作为唯一标识 animatedTexts: [ TypewriterAnimatedText( chatList[index].message!.content.toString(), speed: Duration(milliseconds: 50)) ], totalRepeatCount: 1, ); },
2. 修改聊天列表更新逻辑
将直接替换chatList改为追加新内容,同时清空输入框优化交互:
suffixIcon: IconButton( onPressed: () async { if (textController.text.trim().isEmpty) return; // 空输入不发送请求 setState(() { isTyping = true; }); List<ApiModel> newReply = await apiObj.sentData(textController.text); setState(() { chatList.addAll(newReply); // 追加新回复到聊天列表 isTyping = false; textController.clear(); // 清空输入框 }); }, icon: Icon(Icons.send)),
3. 可选:添加自动滚动到底部(体验优化)
如果聊天记录较多,可在每次添加新内容后自动滚动到列表底部:
// 先在状态类中定义滚动控制器 ScrollController _scrollController = ScrollController(); // 在ListView中绑定控制器 ListView.builder( controller: _scrollController, itemCount: chatList.length, // ...其他参数 ) // 在更新列表后添加滚动逻辑 setState(() { chatList.addAll(newReply); isTyping = false; textController.clear(); }); // 延迟执行滚动,确保UI已完成更新 WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController.animateTo( _scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 300), curve: Curves.easeOut, ); });
修改后主代码关键片段
class _MyAppState extends State<MyApp> { bool isTyping = false; TextEditingController textController = TextEditingController(); ApiClass apiObj = ApiClass(); List<ApiModel> chatList = []; ScrollController _scrollController = ScrollController(); // 新增滚动控制器 @override Widget build(BuildContext context) { return MaterialApp( title: "Chat GPT", theme: ThemeData( textSelectionTheme: TextSelectionThemeData(selectionHandleColor: Colors.transparent)), home: Scaffold( appBar: PreferredSize( preferredSize: Size.fromHeight(50), child: AppBar( title: Text("AI ChatBot"), ), ), body: Column( children: [ Text(textController.text), Expanded( child: ListView.builder( controller: _scrollController, itemCount: chatList.length, itemBuilder: (context, index) { return AnimatedTextKit( key: ValueKey(chatList[index].message!.content), animatedTexts: [ TypewriterAnimatedText( chatList[index].message!.content.toString(), speed: Duration(milliseconds: 50)) ], totalRepeatCount: 1, ); }, ), ), if (isTyping) ...[ SpinKitThreeBounce( size: 18, color: Colors.grey, ) ], TextField( controller: textController, decoration: InputDecoration( contentPadding: EdgeInsets.symmetric(horizontal: 10), hintText: "Type your question here...", suffixIcon: IconButton( onPressed: () async { if (textController.text.trim().isEmpty) return; setState(() { isTyping = true; }); List<ApiModel> newReply = await apiObj.sentData(textController.text); setState(() { chatList.addAll(newReply); isTyping = false; textController.clear(); }); WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController.animateTo( _scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 300), curve: Curves.easeOut, ); }); }, icon: Icon(Icons.send)), filled: true, fillColor: Colors.grey, border: InputBorder.none, ), textAlignVertical: TextAlignVertical.center, style: TextStyle(color: Colors.white), cursorColor: Colors.amber, ) ], ), ), ); } }
内容的提问来源于stack exchange,提问作者Mr. Anonymous
相关产品推荐
相关产品推荐

