flutter即时通讯聊天下拉刷新更多消息思路及代码实现

2023-05-16

2021/12/27更新
以下的解决方案会出现一些问题,也是我后面才注意到的。
因为将ListView进行了reverse,所以当消息只有一条的时候,从视图上来看消息都是置于最底部的,就比较不符合我们传统的即时通讯的视图(如微信),虽然这个的下拉效果比较好,但是如果历史消息比较少时,打开就比较违背常理,就不是很好看,所以我就放弃了下面的方案,不进行reverse,下拉获取更多消息这个功能就暂时放弃了,如果有更好的方案的朋友麻烦联系我一下。。。。

以下是原答案:
一、思路回顾
首先,在聊天区域整体是一个可滚动的界面,我们的需求是通过用户下拉手势,即可获取新的聊天记录,并加在原聊天记录的顶端,给用户制造一种无感连接的体验,加载或者加载完毕都要对用户进行信息的提示。

即可以将思路分为以下几步:
1、在有限的高度中,加载二十条聊天记录,形成可以滚动的区域
2、滑动至滚动区域的【顶部】时,调用触发获取新的20条消息的接口,且该过程中顶部有提示文字,“正在加载中…”
3、接口获取数据完毕后,对数据进行必要的处理后,将数据拼接至原数据之中,顶部且有充足的位置留给新给的数据。如果再无新的20条消息,则将提示文字改成“已加载显示全部消息”。

但是以上以一个正常的ListView来实现,便会出现一个问题,当新的数据出现时,将数据通过insertAll方法插入至第0条之前的位置时,便会出现新的数据将旧的数据顶替的效果。至于为什么会出现这一点,我估计是因为我们滑动到顶部时,我们并没有为顶部至第一条消息之间留出一个新的距离,导致滚动距离还停留在顶部,但是数据的后二十条已经变成了新的二十条,所以会出现一个【替换】效果,但是我们需要的是一个拼接效果。

于是我在网络上找到了解决方案(毕竟不是我自己想出来的…),找到的时候还是觉得,还是大家聪明啊。。。。但是我还是想自己再捋一捋整个思路
原文地址:https://cloud.tencent.com/developer/article/1647244

二、正确且最终的实现思路是:
使用Listview,并且flutter的列表滚动还带有了reverse的属性,也就是可以将整个列表进行旋转颠倒,这样我们的底部变成了顶部,顶部其实是列表的底部,在新的数据进行拼接时,就会自动在下面留出一部分距离,也就不会造成替换的效果。
具体思路:
1、当整体历史消息不为空时返回可以滚动的区域,使用ScrollConfiguration包裹Listview,以便实现自己想要的行为。
2、对Listview进行reverse,且itemcount为数据长度+1,留出空位用于显示加载提示信息
3、在数据长度+1 的位置(我们看到的顶部)加载提示信息,其余位置加载消息体
4、对滚动进行监听,当滚动位置大于当前最大滚动距离时,修改加载状态,
5、根据加载状态对加载提示信息进行单独的控制
整个ListView的代码如下:

Widget buildMessageListContainer() {
  if (_historyMessageList.length == 0) {
    return Container(
        height: Adapt.px(50),
        alignment: Alignment.center,
        child: Text(
          '暂无历史消息',
          style: TextStyle(color: Colors.grey, fontSize: Adapt.px(13)),
        ));
  } else {
    return Column(
      children: [
        Expanded(
          child: ScrollConfiguration(
            // color: Colors.green,
            behavior: ChatScrollBehavior(),
            child: ListView.builder(
                controller: _scrollController,
                reverse: true,
                physics: ChatScrollPhysics(
                    parent: AlwaysScrollableScrollPhysics()),
                itemCount: _historyMessageList.length + 1,
                itemBuilder: (BuildContext context, int index) {
                  if (index == _historyMessageList.length) {
                    return loadingView();
                  } else {
                    return getMessageRow(index);
                  }
                }),
          ),
        ),
        SizedBox(
          height: INPUT_CONTAINER_HEIGHT,
        )
      ],
    );
  }
}

ChatScrollPhysics和ChatScrollBehavior是原博主为了优化滚动效果和行为对方法进行了重写。
ChatScrollPhysics:目的是为了实现下滑加载带弹性效果,上滑屏蔽弹性效果
ChatScrollBehavior:使用ScrollConfiguration包裹滑动组件behavior设置成自己实现的behavior。

滚动监听:

void scrollListener() {
  if (_scrollController!.position.pixels >=
      _scrollController!.position.maxScrollExtent) {
    _getMoreData();
  }
}
_scrollController!.addListener(scrollListener);

获取新数据且改变加载提示信息

void _getMoreData() async {
  if (_loadStatus == LoadingStatus.STATUS_IDLE) {
    _loadStatus = LoadingStatus.STATUS_LOADING;
    loadText = '加载中...';
    List moreList = [];
    var sentTime =
        this._historyMessageList[_historyMessageList.length - 1].sentTime;
    var list = await RongImSdk.getHistoryMessage(_groupId, sentTime, 20, 0);
    if (list.length > 0) {
      //去掉第一条,因为第一条已经显示
      for (int i = 1; i < list.length; i++) {
        moreList.add(list[i]);
      }
      if (moreList.length > 0) {
        _loadStatus = LoadingStatus.STATUS_IDLE;
        this._historyMessageList.addAll(moreList);
      } else {
        _loadStatus = LoadingStatus.STATUS_COMPLETED;
        loadText = '已显示全部消息';
      }
    } else {
      _loadStatus = LoadingStatus.STATUS_COMPLETED;
      loadText = '已显示全部消息';
    }
    setState(() {});
  }
}

加载提示信息样式:

Widget loadingView() {
  var loadingTs =
      TextStyle(color: Constants.ITEM_LABEL_COLOR_999, fontSize: 12);
  var loadingText = Padding(
    padding: EdgeInsets.only(left: Adapt.px(0)),
    child: Text(
      loadText,
      style: loadingTs,
    ),
  );
  var loadingIndicator = SizedBox(
    child: CircularProgressIndicator(
        strokeWidth: Adapt.px(2),
        valueColor: AlwaysStoppedAnimation(Colors.blue)),
    width: Adapt.px(12),
    height: Adapt.px(12),
  );
  return Padding(
        padding: EdgeInsets.only(top: Adapt.px(20), bottom: Adapt.px(20)),
        child: Row(
          children: <Widget>[
            _loadStatus == LoadingStatus.STATUS_LOADING
                ? loadingIndicator
                : Text(''),
            loadingText
          ],
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
        ));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

flutter即时通讯聊天下拉刷新更多消息思路及代码实现 的相关文章

  • OpenCV绘图相关操作 C++

    绘制相关知识 lineType线条风格介绍 opencv的线条风格由枚举值描述 xff1a span class token comment type of line span span class token keyword enum s
  • C++单例模式的几种实现

    单例模式 Singleton Pattern 的概念 模式定义 保证一个类仅有一个实例 xff0c 并提供一个访问它的全局访问点 饿汉单例和懒汉单例 常见的单例模式有两个分支 xff0c 饿汉单例和懒汉单例 饿汉单例是指在程序初始化时就把单
  • OpenCV深度图转点云

    需要先进行畸变校正 xff0c 再通过深度图转点云 相机的相关参数需要事先通过标定获得 span class token macro property span class token directive hash span span cl
  • 贝叶斯分类器,什么是朴素贝叶斯,后续为使用贝叶斯实现海量数据的邮件筛选。带源码数据集和解决思路

    朴素贝叶斯分类器 任务 xff1a 理解朴素贝叶斯分类器 实现我们的第一个贝叶斯分类器 使用朴素贝叶斯分类器分类邮件 概率论基础 xff1a 随机变量 xff1a 这个变量的值依赖于概率 抛硬币 xff08 其结果可能是正面 xff0c 也
  • [jetson]jetpack5.1的ubuntu20.04更换为清华源

    为使后续下载安装顺利 xff0c 需要给 Ubuntu 系统进行换源 Ctrl 43 Alt 43 T 打开终端 xff0c 输入如下命令 sudo gedit etc apt sources list 删除原文件内容 xff0c 添加如下
  • Windows系统借助WSL2可使用Linux系统开发

    一 起源 Windows 10 2004 发布后 xff0c WSL2 也可以在正式版 Windows 10 中使用 xff0c 相比于 macOS xff0c WSL2 是一个原生 Linux 环境而非类 unix 环境 xff0c 甚至
  • wiremock基本使用

    进入wiremock官网 xff0c 选择stand alone xff0c 下载jar包 http wiremock org docs running standalone 运行该jar包 xff0c 并设置端口号 xff0c 如 xff
  • 建行笔试题,最少补给品问题

    import java util Scanner public class Main public static void main String args Scanner sc 61 new Scanner System in Strin
  • springboot传递参数并选择激活环境运行jar包

    java jar spring boot demo 0 0 1 SNAPSHOT jar SOME ENV 61 always spring profiles active 61 prod
  • springcloud alibaba

    springcloud alibaba 版本说明 https github com alibaba spring cloud alibaba wiki E7 89 88 E6 9C AC E8 AF B4 E6 98 8E E6 AF 95
  • @JSONField的一些使用基础

    https blog csdn net dmw412724 article details 93761161
  • MyBatis Mapper 传递多个参数

    在pojo类对应的映射文件中 xff0c 对应的参数类型可以省略 传递方式 1 接口正常书写 xff0c 映射文件中SQL语句的占位符必须用 arg0 agr1 或param1 param2 接口 xff1a public Customer
  • MyBatis一对多的左连接查询、分步查询以及插入和删除操作

    例如有两张表 xff0c 分别是客户表和订单表 xff0c 一个客户有多个订单 xff0c 一个订单属于一个客户 两个实体类Customer Order 如下 xff1a package com itlike domain import l
  • 二叉树的构建及递归遍历

    定义结构体 public class Node int value Node left Node right public Node int value Node left Node right this value 61 value th
  • MySQL 多对多条件查询

    两个表 user和role 中间表是user role 查询用户和角色的对应关系 select res user name r role name from select u user name ur role id from user a
  • spring Bean相关配置及对象的生命周期

    名称与表示 xff1a id 使用了约束中的唯一约束 xff0c 里面不能出现特殊字符 name 没有使用唯一约束 xff0c 可以出现特殊字符 xff08 一般不使用 xff09 设置对象生命周期的方法 xff1a init method
  • 新博客开通

    xff01 xff5e 今天终于决定开博客了 并决定把全部觉得重要的东西都记录下来 每次都记录下来 然后一段时间再来总结一次 xff5e 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • mybatis 代码生成器及多表联查的细节

    在使用mybatis代码生成器时 xff0c 若生成的字段要为布尔类型 xff0c 则在设计表时 xff0c 将字段属性设置为tinyint 长度设为1 这样 生成的domain中的 相应字段类型为布尔类型 如数据库中的字段类型为date或
  • yml自定义属性和值

    测试类 xff1a import com spx App import com spx config MyProperties import org junit Test import org junit runner RunWith im
  • 导出数据提示--secure-file-priv选项问题的解决方法

    mysql可使用 into outfile 参数把表中数据导出到csv xff0c 例如可用以下命令把user表的数据导出到user csv 1 select from user into outfile 39 tmp user csv 3

随机推荐