-
-
Notifications
You must be signed in to change notification settings - Fork 46
3、聊天会话
林洵锋 edited this page Sep 24, 2023
·
5 revisions
只需要三个步骤即可实现聊天会话页的列表效果
- 1、聊天数据不满一屏时,顶部显示所有聊天数据
- 2、插入消息时
- 如果最新消息紧靠列表底部时,则插入消息会使列表向上推
- 如果不是紧靠列表底部,则固定到当前聊天位置
步骤一:初始化必要的 ListObserverController
和 ChatScrollObserver
/// 初始化 ListObserverController
observerController = ListObserverController(controller: scrollController)
..cacheJumpIndexOffset = false;
/// 初始化 ChatScrollObserver
chatObserver = ChatScrollObserver(observerController)
// 超过该偏移量才会触发保持当前聊天位置的功能
..fixedPositionOffset = 5
..toRebuildScrollViewCallback = () {
// 这里可以重建指定的滚动视图即可
setState(() {});
};
步骤二:按如下配置 ListView
并使用 ListViewObserver
将其包裹
Widget _buildListView() {
Widget resultWidget = ListView.builder(
physics: ChatObserverClampinScrollPhysics(observer: chatObserver),
shrinkWrap: chatObserver.isShrinkWrap,
reverse: true,
controller: scrollController,
...
);
resultWidget = ListViewObserver(
controller: observerController,
child: resultWidget,
);
return resultWidget;
}
步骤三:插入或删除消息前,调用 ChatScrollObserver
的 standby
方法
onPressed: () {
chatObserver.standby();
setState(() {
chatModels.insert(0, ChatDataHelper.createChatModel());
});
},
...
onRemove: () {
chatObserver.standby(isRemove: true);
setState(() {
chatModels.removeAt(index);
});
},
默认只处理插入一条消息的情况,如果你需要一次性插入多条,那 standby
需要传入 changeCount
参数
_addMessage(int count) {
chatObserver.standby(changeCount: count);
setState(() {
needIncrementUnreadMsgCount = true;
for (var i = 0; i < count; i++) {
chatModels.insert(0, ChatDataHelper.createChatModel());
}
});
}
注:该功能依赖被插入消息前的最新消息视图做为参照去计算偏移量,所以如果一次性插入的消息数太多,导致该参照消息视图无法得到渲染,则该功能会失效,需要你自己去对 ScrollView
的 cacheExtent
设置合理的值来尽量避免这个问题!
chatObserver = ChatScrollObserver(observerController)
..onHandlePositionResultCallback = (result) {
switch (result.type) {
case ChatScrollObserverHandlePositionType.keepPosition:
// 保持当前聊天消息位置
// updateUnreadMsgCount(changeCount: result.changeCount);
break;
case ChatScrollObserverHandlePositionType.none:
// 对聊天消息位置不做处理
// updateUnreadMsgCount(isReset: true);
break;
}
};
该回调的主要作用:在新增聊天消息时,处理新消息未读数气泡的展示
像 ChatGPT
那样不断变化的生成式消息,在翻看旧消息时也需要保持消息位置,你只需要在 standby
方法中调整一下处理模式即可
chatObserver.standby(
mode: ChatScrollObserverHandleMode.generative,
// changeCount: 1,
);
注: 内部会根据 changeCount
来决定参照的 item
,且仅支持生成式消息为连续的情况。
如果你的生成式消息是不连续的,或者同一时间内即有生成式消息更新,又有增加与删除消息的行为,在这种复杂的情况下,则需要你自己指定参照 item
,且这个处理模式更具有灵活性。
chatObserver.standby(
changeCount: 1,
mode: ChatScrollObserverHandleMode.specified,
refItemRelativeIndex: 2,
refItemRelativeIndexAfterUpdate: 2,
);
- 设置
mode
为.specified
- 设置更新
前
的参照item
的相对下标 - 设置更新
后
的参照item
的相对下标
注: 相对下标指的是当前屏幕中正在显示的 item
所对应的相对下标,如下所示
trailing relativeIndex
----------------- -----------------
| item4 | 4
| item3 | 3
| item2 | 2
| item1 | 1
| item0 | 0
----------------- -----------------
leading
trailing relativeIndex
----------------- -----------------
| item14 | 4
| item13 | 3
| item12 | 2
| item11 | 1
| item10 | 0
----------------- -----------------
leading
请记住,你的 refItemRelativeIndex
和 refItemRelativeIndexAfterUpdate
不论你如何设置,它都应该是指向同一个消息对象!