flutter即时通讯聊天下拉刷新更多消息思路及代码实现
Posted FixUpSth
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flutter即时通讯聊天下拉刷新更多消息思路及代码实现相关的知识,希望对你有一定的参考价值。
一、思路回顾
首先,在聊天区域整体是一个可滚动的界面,我们的需求是通过用户下拉手势,即可获取新的聊天记录,并加在原聊天记录的顶端,给用户制造一种无感连接的体验,加载或者加载完毕都要对用户进行信息的提示。
即可以将思路分为以下几步:
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,
));
以上是关于flutter即时通讯聊天下拉刷新更多消息思路及代码实现的主要内容,如果未能解决你的问题,请参考以下文章