首页 > 解决方案 > 如何在 Flutter 中显示最后的消息

问题描述

我有我正在做的这个项目。这是一个聊天应用程序。我已经能够处理大部分功能,但需要一些帮助。我使用 firebase 作为后端,所有数据都从 firestore 存储和检索,以在聊天中显示消息。我注意到在打开聊天时我没有自动看到最后一条消息,就像它在 whatsapp 或其他聊天应用程序上正常显示的方式一样。例如,如果我输入一条新消息,我希望它是页面底部显示的最后一件事。请帮我检查一下。这是我的代码:

import 'package:chat/constants.dart';
import 'package:chat/utilities/constants.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:emoji_picker/emoji_picker.dart';
import 'package:flutter/material.dart';
import 'package:chat/models/auth.dart';
import 'package:chat/models/message.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

class ChatScreen extends StatefulWidget {
  final AuthImplementation auth;
  final VoidCallback signedOut;

  ChatScreen({
    this.auth,
    this.signedOut,
  });

  @override
  _ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  bool show = false;
  FocusNode focusNode = FocusNode();

  final Firestore _firestore = Firestore.instance;

  TextEditingController messageController = TextEditingController();
  ScrollController scrollController = ScrollController();

  String userName;
  @override
  void initState() {
    super.initState();
    widget.auth.getCurrentUserEmail().then((email) {
      setState(() {
        final String userEmail = email;
        final endIndex = userEmail.indexOf("@");
        userName = userEmail.substring(0, endIndex);
        focusNode.addListener(() {
          if (focusNode.hasFocus) {
            setState(() {
              show = false;
            });
          }
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: new Container(
          padding: new EdgeInsets.all(8.0),
          decoration: new BoxDecoration(
            image: new DecorationImage(
                image: new AssetImage("assets/images/social-logo.png"),
                fit: BoxFit.fill),
            color: Colors.white,
            borderRadius: new BorderRadius.all(new Radius.circular(80.0)),
            border: new Border.all(
              color: Colors.white,
              width: 1.0,
            ),
          ),
        ),
        title: Text("One Gov FX Signal Room",
            style: TextStyle(
              fontSize: 20,
              color: Colors.white,
              fontWeight: FontWeight.bold,
              fontFamily: 'Spartan',
            )),
        backgroundColor: kPrimaryColor,
        actions: <Widget>[
          IconButton(
              icon: FaIcon(FontAwesomeIcons.signOutAlt),
              color: Colors.white,
              onPressed: logOut),
        ],
      ),
      backgroundColor: antiFlashWhite,
      body: WillPopScope(
          child: Column(
            children: <Widget>[
              Container(
                color: Colors.white,
                padding:
                    EdgeInsets.only(left: 10, right: 0, bottom: 10, top: 10),
                child: Row(
                  children: [
                    CircleAvatar(
                      backgroundColor: Colors.white,
                      backgroundImage:
                          AssetImage("assets/images/social-logo.png"),
                    ),
                    SizedBox(
                      width: 50,
                    ),
                    Flexible(
                      child: Column(children: const <Widget>[
                        Text('Message From the Admins'),
                        Text(
                            'Keep your messages polite and do not abuse the channel. Try to keep your discussions within the community guidelines'),
                      ]),
                    )
                  ],
                ),
              ),
              Expanded(
                child: Container(
                  //margin: EdgeInsets.symmetric(horizontal: 5),
                  child: StreamBuilder<QuerySnapshot>(
                      stream: _firestore
                          .collection("messages")
                          .orderBy(
                            "timestamp",
                          )
                          .snapshots(),
                      builder: (context, snapshot) {
                        if (!snapshot.hasData)
                          return Center(
                            child: CircularProgressIndicator(
                              backgroundColor: kPrimaryColor,
                            ),
                          );
                        List<DocumentSnapshot> docs = snapshot.data.documents;

                        List<Widget> messages = docs
                            .map((doc) => Message(
                                  user: doc.data['user'],
                                  text: doc.data['text'],
                                  timestamp: doc.data['timestamp'],
                                  mine: userName == doc.data['user'],
                                ))
                            .toList();
                        return ListView(
                          controller: scrollController,
                          children: messages,
                        );
                      }),
                ),
              ),
              Container(
                color: Colors.white,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    Row(
                      children: <Widget>[
                        IconButton(
                          icon: FaIcon(
                            FontAwesomeIcons.smile,
                            color: kPrimaryColor,
                          ),
                          onPressed: () {
                            focusNode.unfocus();
                            focusNode.canRequestFocus = false;
                            setState(() {
                              show = !show;
                            });
                          },
                        ),
                        Expanded(
                          child: Padding(
                            padding: const EdgeInsets.all(10),
                            child: TextField(
                              focusNode: focusNode,
                              style: TextStyle(
                                fontFamily: 'Poppins',
                                fontSize: 15,
                              ),
                              onSubmitted: (value) => sendChat(),
                              controller: messageController,
                              scrollController: scrollController,
                              keyboardType: TextInputType.multiline,
                              textInputAction: TextInputAction.newline,
                              maxLines: null,
                              cursorColor: kPrimaryColor,
                              decoration: InputDecoration(
                                border: OutlineInputBorder(
                                    borderRadius: BorderRadius.circular(20)),
                                filled: true,
                                hintText: "Say Something. Be Nice...",
                                hintStyle: TextStyle(
                                    fontFamily: 'Montserrat', fontSize: 12),
                              ),
                            ),
                          ),
                        ),
                        IconButton(
                          icon: FaIcon(
                            FontAwesomeIcons.file,
                            color: kPrimaryColor,
                          ),
                          onPressed: () {
                            showModalBottomSheet(
                                backgroundColor: Colors.transparent,
                                context: context,
                                builder: (builder) => bottomsheet());
                          },
                        ),
                        IconButton(
                          icon: FaIcon(
                            FontAwesomeIcons.paperPlane,
                            color: kPrimaryColor,
                          ),
                          onPressed: sendChat,
                        ),
                      ],
                    ),
                    show ? emojiSelect() : Container(),
                  ],
                ),
              ),
            ],
          ),
          onWillPop: () {
            if (show) {
              setState(() {
                show = false;
              });
            } else {
              Navigator.pop(context);
            }
            return Future.value(false);
          }),
    );
  }

  void logOut() async {
    try {
      await widget.auth.signOut();
      widget.signedOut();
    } catch (e) {
      print("error :" + e.toString());
    }
  }

  Future<void> sendChat() async {
    if (messageController.text.length > 0) {
      await _firestore.collection("messages").add({
        'user': userName,
        'text': messageController.text,
        'timestamp': FieldValue.serverTimestamp(),
      });
      messageController.clear();
      scrollController.animateTo(scrollController.position.maxScrollExtent,
          duration: Duration(milliseconds: 300), curve: Curves.easeOut);
    }
  }

  Widget bottomsheet() {
    return Container(
      height: 120,
      width: MediaQuery.of(context).size.width,
      child: Card(
        margin: EdgeInsets.all(0),
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              GestureDetector(
                  child: iconcreation(
                Icons.analytics,
                Colors.black,
                "Analysis",
              )),
              SizedBox(
                width: 40,
              ),
              iconcreation(Icons.report, Colors.black, "Report User"),
              SizedBox(
                width: 40,
              ),
              iconcreation(Icons.link, Colors.black, "Link")
            ],
          ),
        ),
      ),
    );
  }

  Widget iconcreation(IconData icon, Color color, String text) {
    return InkWell(
      onTap: () {},
      child: Column(
        children: [
          CircleAvatar(
            backgroundColor: color,
            radius: 30,
            child: Icon(
              icon,
              size: 29,
              color: Colors.white,
            ),
          ),
          SizedBox(height: 5),
          Text(text),
        ],
      ),
    );
  }

  Widget emojiSelect() {
    return EmojiPicker(
        rows: 4,
        columns: 7,
        onEmojiSelected: (emoji, category) {
          print(emoji);
          setState(() {
            messageController.text = messageController.text + emoji.emoji;
          });
        });
  }
}

这是应用程序的示例图像: 应用程序的 屏幕截图

标签: firebasefluttermessaging

解决方案


descending: true在时间戳之后添加。

喜欢Expanded( child: Container( //margin: EdgeInsets.symmetric(horizontal: 5), child: StreamBuilder<QuerySnapshot>( stream: _firestore .collection("messages") .orderBy( "timestamp", descending: true ) .snapshots(), builder: (context, snapshot) { if (!snapshot.hasData) return Center( child: CircularProgressIndicator( backgroundColor: kPrimaryColor, ), );


推荐阅读