Flutter实战一Flutter聊天应用(十八)

119 篇文章 9 订阅
82 篇文章 1415 订阅

上一篇文章中,我们完成了基本的添加聊天功能,但是还没有在聊天列表显示添加的新聊天,在这篇文章中我们将实现这个功能——在聊天列表中展示所有的聊天。

首先,我们在/lib目录下新建一个group_chat_list_body.dart文件。在group_chat_list_body.dart中编写一个有状态控件GroupChatListBody,传递两个参数,phone(手机号码)和myName(姓名),手机号码将用于在Firebase实时数据库中访问“/chats/$phone”,以读取当前用户的聊天列表。

import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'chat_screen.dart';
import 'prompt_wait.dart';

class GroupChatListBody extends StatefulWidget {
  GroupChatListBody({
    this.phone,
    this.myName,
    Key key,
  })
      : super(key: key);
  final String phone;
  final String myName;
  @override
  _GroupChatListBodyState createState() => new _GroupChatListBodyState(phone);
}

class _GroupChatListBodyState extends State<GroupChatListBody> {
  _GroupChatListBodyState(this._phone);
  final String _phone;
  @override
  Widget build(BuildContext context) {
    return new Text("聊天列表");
  }
}

回到group_chat_list.dart文件中,在_GroupChatListState中修改一下build方法,使用我们在前面自定义的有状态控件GroupChatListBody。如果参数phone为空,说明还没有读取到用户的手机号码,则暂时显示空白,直到参数phone不为空才显示GroupChatListBody控件。

class _GroupChatListState extends State<GroupChatList> {
  //...
  Widget build(BuildContext context) {
    //...
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("纸聊"),
          centerTitle: true,
          elevation: 0.0,
        ),
        drawer: drawer,
        body: new Center(
          child: phone == "null"
              ? null
              : new GroupChatListBody(phone: phone, myName: name),
        ),
        //...
    );
  }
}

再回到group_chat_list_body.dart文件中,我们新创建一个GroupChatListBodyItem类,这是一个无状态控件,用于展示具体的一个聊天。这个控件所需要的参数有点多,name(对方的名称)、lastMessage(最新的消息)、timestamp(时间戳)、messages(“/messages/$messages”)、myName(名称)、myPphone(手机号码)和shePphone(对方的手机号码)。

GroupChatListBodyItem的顶层是一个GestureDetector控件,其onTap属性是一个匿名方法,内容是导航到一个新屏幕,而新屏幕的内容是ChatScreen控件。ChatScreen控件是应用程序的第一个屏幕,我们只需要修改一下里面的内容就可以直接调用,具体的修改会在下一篇文章中讲解,或者可以在GitHub上直接查看。

class GroupChatListBodyItem extends StatelessWidget {
  GroupChatListBodyItem(
      {this.name,
      this.lastMessage,
      this.timestamp,
      this.messages,
      this.myName,
      this.myPphone,
      this.shePphone});
  final String name;
  final String lastMessage;
  final String timestamp;
  final String messages;
  final String myName;
  final String myPphone;
  final String shePphone;

  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
        onTap: () {
          Navigator.of(context).push(new MaterialPageRoute<Null>(
            builder: (BuildContext context) {
              return new ChatScreen(
                  messages: messages,
                  myName: myName,
                  sheName: name,
                  myPphone: myPphone,
                  shePphone: shePphone);
            },
          ));
        },
        child: new Container(
            decoration: new BoxDecoration(),
            padding: new EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
            child: new Row(
              children: <Widget>[
                new CircleAvatar(
                    child: new Text(name[0]),
                    backgroundColor: Theme.of(context).buttonColor),
                new Flexible(
                    child: new Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    new Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: <Widget>[
                          new Text("  " + name, textScaleFactor: 1.2),
                          new Text(ReadableTime(timestamp),
                              textAlign: TextAlign.right,
                              style: new TextStyle(
                                  color: Theme.of(context).hintColor)),
                        ]),
                    new Container(
                        padding: new EdgeInsets.only(top: 2.0),
                        child: new Text("  " + lastMessage,
                            overflow: TextOverflow.ellipsis,
                            style: new TextStyle(
                                color: Theme.of(context).hintColor))),
                  ],
                ))
              ],
            )));
  }
}

这里写图片描述

前面的GroupChatListBodyItem中有一个timestamp参数,在Firebase实时数据库是以“2017-08-14 17:16:11.65”的时间戳格式保存的,并非直观的可读格式,因此我们需要进行格式转换。在prompt_wait.dart文件中写一个通用方法ReadableTime,将给定的时间戳转换成直观的可读形式,在prompt_wait.dart中添加以下代码。

String ReadableTime(String timestamp) {
  List<String> timeList = timestamp.split(" ");
  List<String> times = timeList[1].split(":");
  String time;
  if (new DateTime.now().toString().split(" ")[0] == timeList[0]) {
    if (int.parse(times[0]) < 6) {
      time = "凌晨${times[0]}:${times[1]}";
    } else if (int.parse(times[0]) < 12) {
      time = "上午${times[0]}:${times[1]}";
    } else if (int.parse(times[0]) == 12) {
      time = "中午${times[0]}:${times[1]}";
    } else {
      time =
          "下午${(int.parse(times[0])- 12).toString().padLeft(2,'0')}:${times[1]}";
    }
  } else {
    time = timeList[0];
  }
  return time;
}

_GroupChatListBodyState中覆盖initState方法,使控件在初始化时访问Firebase实时数据库中的“chats/$_phone”。将setPersistenceEnabled设置为true,开启数据库的持久性设置,同时调用keepSynced(true),使数据将自动下载并保持同步。

class _GroupChatListBodyState extends State<GroupChatListBody> {
  //...
  DatabaseReference _chatsReference;

  @override
  void initState() {
    super.initState();
    _chatsReference = FirebaseDatabase.instance.reference().child('chats/$_phone');
    FirebaseDatabase.instance.setPersistenceEnabled(true);
    _chatsReference.keepSynced(true);
  }
  //...
}

最后修改_GroupChatListBodyState中的build方法,使用FirebaseAnimatedList控件读取Firebase实时数据库。参数query设置查询位置,sort设置排序,这里设置成按时间戳排序,defaultChild设置读取时的等待动画。itemBuilder会遍历一次查询到的数据,将这些数据分别创建一个GroupChatListBodyItem控件。

class _GroupChatListBodyState extends State<GroupChatListBody> {
  //...
  @override
  Widget build(BuildContext context) {
    return new FirebaseAnimatedList(
      query: _chatsReference,
      sort: (DataSnapshot a, DataSnapshot b) =>
          b.value["timestamp"].compareTo(a.value["timestamp"]),
      defaultChild: new CircularProgressIndicator(),
      itemBuilder: (BuildContext context, DataSnapshot snapshot,
          Animation<double> animation) {
        return new SizeTransition(
          sizeFactor: animation,
          child: new GroupChatListBodyItem(
            name: snapshot.value["name"],
            lastMessage: snapshot.value["lastMessage"],
            timestamp: snapshot.value["timestamp"],
            messages: snapshot.value["messages"],
            myName: widget.myName,
            myPphone: _phone,
            shePphone: snapshot.value["phone"],
          ),
        );
      },
    );
  }
}

这里写图片描述

大家可以在GitHub上直接查看group_chat_list_body.dart文件group_chat_list.dart文件chat_screen.dart文件的代码。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何小有

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值