Flutter   发布时间:2022-05-03  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Flutter实战一Flutter聊天应用(十七)大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

在正文开始之前,我们先组织一下数据,所有Firebase实时数据库的数据都被存储为Json对象。我们可以将该数据库视为云托管Json树,该数据库sql数据库不同,没有任何表格或记录。当我们将数据添加至Json树时,它变为现有Json结构中的一个节点。

然Firebase实时数据库允许嵌套数据的深度多达32层,然而,当我们提取数据库中某个位置的数据时,也会检索所有子节点。另外,当我们向某用户授予数据库中某个节点的读写访问权时,也会将该节点下所有数据的访问权授予该用户

在Firebase实时数据库中,数据结构最佳做法是平展数据结构,数据被拆分到不同路径(又称反规范化),可以根据需要通过不同调用有效地下载。即使列表含有成千上万条记录,也可单独提取显示,从而确保UI 的及时响应和速度。

{
    "users": { "1380001": { "email": "xingmi@163.com","name": "小明","password": "123456","@H_51_11@phone": "1380001" },"1380002": { "..": ".." },"1380003": { "..": ".." } },"chats": { "1380001": { "1380002": { "name": "小红","@H_51_11@phone": "1380002","messages": "13800011380002","lastmessage": "电路好像出问题了!","timestamp": 1459361875666,"activate": "true" },"1380003": { "name": "小刚","@H_51_11@phone": "1380003","messages": "13800011380003","lastmessage": "发现问题,有人把地线和火线接反","activate": "false" } },"messages": { "13800011380002": { "Ph6dARrtdEAUY5PDL2gt": { "name": "小红","message": "电路好像出问题了!" },"x415NpxFZM2CjibRMCcL": { "..": ".." } },"13800011380003": { "..": ".." },"13800031380002": { "..": ".." } } }

在@R_846_9616@程序中,用户个人资料位于“/users”路径中。现在有“/users/1380001”这个账户,它在“/chats/1380001”下检索所有的会话,再通过“/chats/1380001/messages”的值,在“/messages”中读取这个会话的所有聊天消息。

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

上一篇文章中,我们实现了聊天列表屏幕的基本UI,在这一篇文本中,会具体实现添加会话的功能。具体实现则是当用户点击右下方的添加按钮时,会进入到添加会话屏幕,因此我们需要在/lib目录下新建一个add_session.dart文件,并添加以下代码

import 'package:Flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'dart:async';
import 'prompt_wait.dart';

class AddSession extends StatefulWidget {
  AddSession(this.myPhonE);
  final String myPhone;

  @override
  State createState() => new _AddSessionState(myPhonE);
}

class _AddSessionState extends State<AddSession> {
  _AddSessionState(this._myPhonE);
  final String _myPhone;

  @override
  Widget build(BuildContext context) {
    return new SimpleDialog(title: new Text("添加会话"),children: <Widget>[
      new Text("这里用来放一些相关控件");
    ]);
  }
}

添加add_session.dart文件后,我们需要把聊天列表屏幕中的添加按钮与添加会话屏幕联系起来。修改group_chat_list.dart文件添加下面的代码,在用户点击按钮后,就会跳转添加会话屏幕。这里传递了当前账户的手机号码给添加会话屏幕,使我们能访问对应账户的数据节点,以便添加修改数据。

//...
import 'add_session.dart';
//...
class _GroupChatListState extends State<GroupChatList> {
  //...
  void _floaTingButtonCallBACk() {
    showDialog<Null>(
        context: context,barrierDismissible: false,child: new AddSession(phonE));
  }
  //...
  Widget build(BuildContext context) {
  //...
    return new Scaffold(
        //...
        floaTingActionButton: new FloaTingActionButton(
            BACkgroundColor: Colors.orange[800],elevation: 0.0,onPressed: _floaTingButtonCallBACk,child: new Icon(Icons.person_add)));
  }
}

回到add_session.dart文件中,在_AddSessionState添加一个_findUser方法,用于查找用户是否存在,如果真实存在,则保存这个用户的手机号码和名称,用于给用户展示搜索结果

class _AddSessionState extends State<AddSession> {
  //...
  final usersReference = FirebaseDatabase.instance.reference().child('users');
  String _searchUsername = "";
  String _searchPhone = "";
  //...
  Future<int> _findUser(String phonE) async {
    return await usersReference
        .child(phonE)
        .once()
        .then((DataSnapshot onvalue) {
      if (onValue.value != null) {
        _searchUsername = onValue.value["name"];
        _searchPhone = onValue.value["phone"];
        return 1;
      } else {
        return 0;
      }
    });
  }
  //...
}

我们还需要一个处理用户点击搜索按钮的事件,在_AddSessionState添加一个_handleFind方法,用于判断用户输入的手机号码是否格式正确,确定没有格式问题,再调用上面的_findUser方法,在数据库中查找该手机号码的账户,最后根据返回结果做对应操作。

class _AddSessionState extends State<AddSession> {
  //...
  final TextEdiTingController _phoneController = new TextEdiTingController();
  //...
  void _handleFind() {
    FocusScope.of(context).requestFocus(new Focusnode());
    if (_phoneController.text.isEmpty) {
      showmessage(context,"手机号码不能为空!");
      return;
    } else if (_phoneController.text.trim() == widget.myPhonE) {
      showmessage(context,"这是你的手机号码哦!");
      return;
    } else if (_phoneController.text.trim().length < 7 ||
        _phoneController.text.trim().length > 12) {
      showmessage(context,"手机号码的格式不正确!");
      return;
    }
    showDialog<int>(
            context: context,child: new ShowAwait(_findUser(_phoneController.text)))
        .then((int onvalue) {
      if (onValue == 0) {
        showmessage(context,"该用户不存在!");
      } else if (onValue == 1) {
        setState(() {});
      }
    });
  }
  //...
}

现在我们在build方法添加手机号码输入框与搜索按钮,并将搜索按钮的点击事件设置成上面的_handleFind方法用户一但点击搜索按钮,首先会判断手机号码格式,然后再搜索是否有该用户并保存用户信息。

class _AddSessionState extends State<AddSession> {
  //...
  @override
  Widget build(BuildContext context) {
    return new SimpleDialog(title: new Text("添加会话"),children: <Widget>[
      new Container(
          margin: const EdgeInsets.symmetric(horizontal: 23.0),child: new Row(
            children: <Widget>[
              new Flexible(
                  child: new TextField(
                controller: _phoneController,keyboardType: TexTinputType.phone,decoration:
                    new InputDecoration.collapsed(hintText: '点击此处输入手机号码'),)),new IconButton(
                  icon: new Icon(Icons.search),onPressed: () {
                    _handleFind();
                  }),],]);
  }
}

上面的代码中,如果手机号码为真实账户,我们会保存账户信息,所以我们还需要将搜索到的账户信息展示给用户。在build方法添加一个展示用户信息的自定义控件。

class _AddSessionState extends State<AddSession> {
  //...
  @override
  Widget build(BuildContext context) {
    return new SimpleDialog(title: new Text("添加会话"),children: <Widget>[
      //...
      _searchUsername == ""
          ? new Text("")
          : new Container(
              margin: const EdgeInsets.symmetric(horizontal: 23.0),child: new Row(
                children: <Widget>[
                  new CircleAvatar(
                      child: new Text(_searchUsername[0]),BACkgroundColor: Theme.of(context).buttonColor),new Flexible(
                      child: new column(
                    crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[
                      new Text(
                        " " + _searchUsername,textScaleFactor: 1.2,overflow: TextOverflow.ellipsis,),new Text(" " + _searchPhonE)
                    ],))
                ],]);
  }
}

我们在_AddSessionState添加一个_addSession方法,用于在“/chats/$user/”下添加一个会话记录。在添加之前,还需要判断是否已经存在该记录,如果已经存在,说明已经添加过这个会话了,这时我们再判断该条记录的activate值,如果是true就说明现在用户的聊天列表中有该条会话,否则说明用户已经删除该会话。

class _AddSessionState extends State<AddSession> {
  //...
  final chatsReference = FirebaseDatabase.instance.reference().child('chats');
  //...
  Future<int> _addSession() async {
    return await chatsReference
        .child('$_myPhone/$_searchPhone')
        .once()
        .then((DataSnapshot onvalue) {
      if (onValue.value == null) {
        chatsReference.child('$_myPhone/$_searchPhone').set({
          "name": _searchUsername,"phone": _searchPhone,"messages": "$_myPhone$_searchPhone","lastmessage": "一起来聊天吧!","activate": "true"
        });
        return 1;
      } else {
        if (onValue.value["activate"] == truE) {
          print("跳转到对应的聊天窗口");
          return 0;
        } else {
          print("移除以前的记录,创建一条新记录");
          return 2;
        }
      }
    });
  }
  //...
}

现在添加一个处理用户点击添加按钮的事件,在_AddSessionState添加一个_handleAppend方法,用于获取_addSession方法的返回值,并做对应的操作。这里关于添加的流程还没有完成,我们会在完成聊天列表屏幕之后再写这些内容

class _AddSessionState extends State<AddSession> {
  //...
  void _handleAppend() {
    showDialog<int>(
        context: context,barrierDismissible: false,child: new ShowAwait(_addSession())).then((int onvalue) {
      if (onValue == 1) {
        print("会话创建成功,返回到聊天列表屏幕");
      }
    });
  }
  //...
}

最后,我们在build方法增加一个取消按钮和添加按钮,其中添加按钮在用户没有搜索到好友之前为不可点击状态,搜索到好友之后才是可点击状态。

class _AddSessionState extends State<AddSession> {
  //...
  @override
  Widget build(BuildContext context) {
    return new SimpleDialog(title: new Text("添加会话"),children: <Widget>[
      //...
      new Container(
          margin: const EdgeInsets.only(top: 18.0),child: new Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,children: <Widget>[
              new RaisedButton(
                elevation: 0.0,onPressed: () {
                  Navigator.of(context).pop();
                },colorBrightness: Brightness.dark,child: const Text('取消'),new RaisedButton(
                elevation: 0.0,onPressed: _searchUsername == "" ? null : _handleAppend,colorBrightness:
                    _searchUsername == "" ? Brightness.light : Brightness.dark,child: const Text('添加'),))
    ]);
  }
}

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

大家可以在GitHub上直接查看add_session.dart文件代码

大佬总结

以上是大佬教程为你收集整理的Flutter实战一Flutter聊天应用(十七)全部内容,希望文章能够帮你解决Flutter实战一Flutter聊天应用(十七)所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。