- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在用 firebase 构建一个聊天应用程序,我目前正在将每条消息作为文档存储在 firebase 的集合中。我使用 StreamBuilder 来获取最新消息并显示它们。我想在收到和发送新消息时添加动画。我曾尝试使用 Animatedlist,但是,我不知道如何使其与 StreamBuilder 一起使用。据我了解,每次添加新消息时,我都必须调用 insertItem 函数。有没有更聪明的方法来做到这一点?或者这将如何实现?
这是我到目前为止:
class Message {
final String uid;
final String message;
final Timestamp timestamp;
Message({this.uid, this.timestamp, this.message});
}
class MessagesWidget extends StatefulWidget {
final String receiver;
MessagesWidget({@required this.receiver});
@override
_MessagesWidgetState createState() => _MessagesWidgetState();
}
class _MessagesWidgetState extends State<MessagesWidget>{
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
Tween<Offset> _offset = Tween(begin: Offset(1,0), end: Offset(0,0));
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: StreamBuilder<List<Message>>(
stream: DatabaseService(uid: user.uid).getMessages(widget.receiver),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Loading();
default:
final messages = snapshot.data;
return messages.isEmpty
? SayHi(userID: widget.receiver,)
: AnimatedList(
key: _listKey,
physics: BouncingScrollPhysics(),
reverse: true,
initialItemCount: messages.length,
itemBuilder: (context, index, animation) {
final message = messages[index];
return SlideTransition(
position: animation.drive(_offset),
child: MessageWidget(
message: message,
userID: widget.receiver,
isCurrentUser: message.uid == user.uid,
),
);
},
);
}
}),
),
SizedBox(
height: 10,
),
NewMessage(
receiver: widget.receiver,
)
],
),
);
}
}```
最佳答案
您可以更新小部件的 State
对此:
class _MessagesWidgetState extends State<MessagesWidget> {
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
Tween<Offset> _offset = Tween(begin: Offset(1, 0), end: Offset(0, 0));
Stream<List<Message>> stream;
List<Message> currentMessageList = [];
User user;
@override
void initState() {
super.initState();
user = Provider.of<User>(context, listen: false);
stream = DatabaseService(uid: user.uid).getMessages(widget.receiver);
stream.listen((newMessages) {
final List<Message> messageList = newMessages;
if (_listKey.currentState != null &&
_listKey.currentState.widget.initialItemCount < messageList.length) {
List<Message> updateList =
messageList.where((e) => !currentMessageList.contains(e)).toList();
for (var update in updateList) {
final int updateIndex = messageList.indexOf(update);
_listKey.currentState.insertItem(updateIndex);
}
}
currentMessageList = messageList;
});
}
@override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: StreamBuilder<List<Message>>(
stream: stream,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Loading();
default:
final messages = snapshot.data;
return messages.isEmpty
? SayHi(
userID: widget.receiver,
)
: AnimatedList(
key: _listKey,
physics: BouncingScrollPhysics(),
reverse: true,
initialItemCount: messages.length,
itemBuilder: (context, index, animation) {
final message = messages[index];
return SlideTransition(
position: animation.drive(_offset),
child: MessageWidget(
message: message,
userID: widget.receiver,
isCurrentUser: message.uid == user.uid,
),
);
},
);
}
}),
),
SizedBox(
height: 10,
),
NewMessage(
receiver: widget.receiver,
)
],
),
);
}
}
另外,更新您的
Message
类到下面的代码:
// Using the equatable package, remember to add it to your pubspec.yaml file
import 'package:equatable/equatable.dart';
class Message extends Equatable{
final String uid;
final String message;
final Timestamp timestamp;
Message({this.uid, this.timestamp, this.message});
@override
List<Object> get props => [uid, message, timestamp];
}
说明:
State
上面的代码执行以下操作:
currentMessageList
外建方法currentMessageList
中的前一个列表进行比较。 . AnimatedList
特定索引处的小部件 updateIndex
. Message
上面的代码执行以下操作:
==
运算符和对象 hashcode
允许在此行中进行检查:List<Message> updateList = messageList.where((e) => !currentMessageList.contains(e)).toList();
按预期工作。 [如果不覆盖这些 getter,检查将失败,因为两个不同的 Message
具有相同值的对象将不相等]。 关于flutter - 在 StreamBuilder 中使用 AnimatedList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67929154/
我正在尝试计算未读消息的数量。在第一个 streambuilder 中,我需要获取所有与第一个查询匹配的文档 ID。 然后,在该文档 ID 中,我可以访问该文档中的子集合并执行另一个查询。然后我需要访
我正在构建一个应用程序,该应用程序大量使用 streambuilder 来从应用程序中的多个页面的 Firestore 获取实时数据。 由于没有流关闭/流订阅取消方法,假设当框架处理小部件时,stre
在注册过程中,我正在构建的应用程序中为每个“用户”文档创建了一个子集合,最多包含100个文档。 我正在尝试用StreamBuilder显示这些子集合文档。 我有一个无法解决的奇怪错误。用户首次查看时,
我的 StreamBuilder 在 View 中: Widget build(BuildContext context) { print("rebuilding..."); // as of
目前,我有一个 StreamBuilder 从 Firebase 为群消息应用程序提取数据。我有一个 snapshot.hasData 检查以确保在显示消息之前有数据。问题在于,当 setState
我正在使用 http库以下载图像。 final client = http.Client(); final _response = await client.send(http.Request('GE
StreamBuilder每当它获得新事件时都会重建。这会导致导航( Navigator.push )出现问题,因为如果在导航时接收到新事件,则此触发器重建。因为在构建小部件树时尝试导航,这将抛出 e
考虑以下代码: StreamBuilder _createDataStream(){ return StreamBuilder( stream: Firestore.i
我正在尝试弄清楚如何将以下数据放入数据表中,但我真的很挣扎,因为它不断重复标题 import 'dart:async'; import 'dart:convert'; import 'package:
我遇到了一个问题,我的流生成器只触发一次。 我正在尝试根据用户选择的主题将我的 bottomNavigationBar 配置为不同的颜色。 为此,我有一个页面,用户可以在其中决定是使用浅色主题还是
以下代码按预期构建和运行——当用户键入内容时,会显示一条错误消息,直到该字符串通过电子邮件验证格式。 Widget emailField(){ return StreamBuilder( stre
我创建了这段代码,我想要发生的是当我按下按钮时我希望饼图用新值重新渲染(应该是旧值但食物值增加 1)我正在使用 pie_chart: 0.8.0 包中的饼图。Deposit 只不过是一个 pojo(S
我有一个页面,我在其中使用 Bloc 从上面的搜索栏中获取文本,以根据输入的文本过滤下面的列表。 当我第一次进入页面时,Bloc 和流都按预期工作,但是,当我弹出它并返回页面时,我可以看到数据正在通过
我的 ApplicationBloc 是小部件树的根。在 bloc 的构造函数中,我正在收听来自存储库的流,其中包含从 JSON 解码的模型并将它们转发到另一个流,该流由 StreamBuilder
我有一个名为 RootContainer 的小部件,它接收一个 Widget child 并将其包装在 StreamBuilder 中: class RootContainer extends Sta
我正在尝试使用 StreamBuilder 从我的 api 中获取数据,这就是我所做的 loadProduct(String categoryId, int limit, int offset) a
我只是在测试来自 GPS 的一些流。我可以直接插入 gps 流,但我想暂时将其分开。所以我可以将 StreamBuilder 与我自己创建的流一起使用。 这一切似乎都在工作,但 Streambuild
当我在 Flutter 中使用 BLOC 时,例如: class StreamText extends StatelessWidget { StreamText( this.stream,
我写了一些简化的代码,我希望 firestore 数据的条件能够更新父小部件。 我收到错误:在构建期间调用了 setState() 或 markNeedsBuild()。 如何从 StreamBuil
我在有状态小部件中有一个 streamBuilder,它从服务器异步获取数据。此外,我有一个收集这些数据的列表。 StreamBuilder( stream: myStream.stream,
我是一名优秀的程序员,十分优秀!