首页 > 解决方案 > 不透明度较低的聊天气泡,表示消息正在发送到 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),
                    ),
                  ),
                ),
              ],
            ),
          ) 
          ),
    );
  }
}

标签: firebaseflutterdartgoogle-cloud-firestorechat

解决方案


我认为您最初可以在每次用户尝试发送消息时将气泡稍微不透明的气泡作为默认值,然后使用该.then()方法更新气泡颜色,如果消息已成功发送并.catch()触发错误图标/吐司,如果由于某些错误,消息未发送。


推荐阅读