firebase - 不透明度较低的聊天气泡,表示消息正在发送到 Firestore Flutter
问题描述
我正在尝试使用 firestore 制作聊天应用程序。我已经完成了聊天应用程序所需的一切,例如使用 StreamBuilder 发送消息和接收消息。但是现在,当输入和发送消息时,StreamBuilder
小部件中的聊天气泡会在 firestore 执行查询后更新。如何显示一个不透明度稍低的临时聊天气泡,表示正在发送的消息就像我们在几乎每个具有聊天功能的应用程序上看到的一样?
以上是我试图达到的结果。与内容的最后一个聊天气泡okay. what's up?
应该具有较少的不透明度,直到它在 Firestore 上更新并在更新后变为完全不透明。如果不是什么替代方法,我应该如何使用 StreamBuilder 来解决这个问题?
代码:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:openmind/utils/constants.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MaterialApp(
home: ChatScreen(),
),
);
}
class ChatScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return ChatScreenState();
} //
}
// Add the ChatScreenState class definition in main.dart.
class ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
final TextEditingController _textController = TextEditingController();
Stream firestoreStream = FirebaseFirestore.instance
.collection("chats")
.doc("david_aaron")
.collection("david_aaron")
.orderBy('timestamp', descending: true)
.snapshots();
void _handleSubmitted(String text) async{
await FirebaseFirestore.instance
.collection("chats")
.doc("david_aaron")
.collection("david_aaron")
.add({
"content":text
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Friendlychat")),
body: Column(
children: <Widget>[
Expanded(
child: StreamBuilder(
stream: firestoreStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
QuerySnapshot doc = snapshot.data as QuerySnapshot;
List<String> msgs = [];
doc.docs.forEach((e) {
Map s = e.data() as Map<String, dynamic>;
msgs.add(s['content']);
});
// return Container(child: Text("DONE"));
return Flexible(
child: ListView.builder(
padding: EdgeInsets.all(8.0), //
reverse: true, //
itemBuilder: (_, int index) => ChatMessage(
animate: index == 0,
key: UniqueKey(),
text: msgs[index],
), //
itemCount: msgs.length, //
), //
);
}
return Center(child: Constants.loadingIndicator);
}),
),
Divider(height: 1.0), //
Container(
//
decoration: BoxDecoration(color: Theme.of(context).cardColor), //
child: _buildTextComposer(), //modified
), //
], //
), //
);
}
Widget _buildTextComposer() {
return IconTheme(
//
data: IconThemeData(color: Theme.of(context).colorScheme.secondary), //
child: Container(
//modified
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: <Widget>[
Flexible(
child: TextField(
controller: _textController,
onChanged: (String text) {
},
onSubmitted: _handleSubmitted,
decoration:
const InputDecoration.collapsed(hintText: "Send a message"),
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 4.0),
child: IconButton(
icon: Icon(Icons.send),
onPressed: () =>
_handleSubmitted(_textController.text) //modified
),
),
],
),
), //
);
}
}
class ChatMessage extends StatefulWidget {
ChatMessage({
Key? key,
required this.text,
this.animate = false,
}) : super(key: key);
final String text;
final bool animate;
@override
State<ChatMessage> createState() => _ChatMessageState();
}
class _ChatMessageState extends State<ChatMessage>
with TickerProviderStateMixin {
late AnimationController animationController;
late double opacity;
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: widget.animate ? 800 : 0));
opacity = .7;
animationController.addListener(() {
if (animationController.isCompleted) {
print("completed");
setState(() {
opacity = 1;
});
}
});
animationController.forward();
}
@override
void dispose() {
super.dispose();
animationController.dispose();
}
@override
Widget build(BuildContext context) {
return Opacity(
opacity: widget.animate ? opacity : 1,
child: SizeTransition(
sizeFactor: CurvedAnimation(
parent: animationController,
curve: Curves.linearToEaseOut,
),
axisAlignment: 0.0,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 200,
height: 40,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: const EdgeInsets.only(left: 8.0, top: 8),
child: Container(
child: Text(widget.text),
),
),
),
],
),
)
),
);
}
}
解决方案
我认为您最初可以在每次用户尝试发送消息时将气泡稍微不透明的气泡作为默认值,然后使用该.then()
方法更新气泡颜色,如果消息已成功发送并.catch()
触发错误图标/吐司,如果由于某些错误,消息未发送。
推荐阅读
- java - 如何在 Recyclerview 中刷新项目位置以进行过滤?
- android - 现有应用程序中的 React Native 更新版本
- mongodb - 如何将“类型”信息复制到 mongo 聚合和查找中的“实例”中......并保留原始列表?
- python - 在 docker 中使用 django 运行 tika python
- python - Python/Numpy:如何使用重复实例重新编号现有数组?
- finite-automata - 不包含 101101 作为子字符串的字符串的 DFA
- testing - 使用 Jooq 进行集成测试
- amazon-web-services - AWS X-Ray Crossacount 数据收集
- angular - 使用 Angular 应用程序在 Azure DevOps 中构建发布管道 - 找不到包含 package.json 的工作文件夹
- java - 闹钟:重复 setAlarmClock()