@@ -167,6 +167,7 @@ void main() {
167167
168168 testWidgets ('Keeping position with customAdjustPositionDelta' ,
169169 (tester) async {
170+ GlobalKey <ChatListViewState > key = GlobalKey ();
170171 final scrollController = ScrollController ();
171172 final observerController = ListObserverController (
172173 controller: scrollController,
@@ -178,6 +179,7 @@ void main() {
178179 const double normalItemHeight = 100 ;
179180
180181 Widget widget = ChatListView (
182+ key: key,
181183 scrollController: scrollController,
182184 observerController: observerController,
183185 chatScrollObserver: chatScrollObserver,
@@ -207,6 +209,35 @@ void main() {
207209 final displayingChildModelList =
208210 observeResult? .displayingChildModelList ?? [];
209211 expect (displayingChildModelList, isNotEmpty);
212+ expect (observeResult? .firstChild? .index, 0 );
213+ expect (observeResult? .firstChild? .leadingMarginToViewport, 0 );
214+
215+ // Check adjustPosition.
216+ key.currentState? .updateData (
217+ index: 1 ,
218+ needSetState: true ,
219+ );
220+ double ? adjustPosition;
221+ await chatScrollObserver.standby (
222+ mode: ChatScrollObserverHandleMode .specified,
223+ refIndexType: ChatScrollObserverRefIndexType .itemIndex,
224+ refItemIndex: 0 ,
225+ refItemIndexAfterUpdate: 0 ,
226+ customAdjustPositionDelta: (model) {
227+ adjustPosition = model.adjustPosition;
228+ return null ;
229+ },
230+ );
231+ await tester.pumpAndSettle ();
232+ expect (adjustPosition, 0 );
233+
234+ result = await observerController.dispatchOnceObserve (
235+ isForce: true ,
236+ isDependObserveCallback: false ,
237+ );
238+ observeResult = result.observeResult;
239+ expect (observeResult? .firstChild? .index, 0 );
240+ expect (observeResult? .firstChild? .leadingMarginToViewport, 0 );
210241
211242 final targetIndex = displayingChildModelList.last.index + 1 ;
212243 // Jump to targetIndex and align its bottom with the viewport bottom.
@@ -261,6 +292,7 @@ void main() {
261292 refItemIndex: refItemIndex,
262293 refItemIndexAfterUpdate: refItemIndex,
263294 customAdjustPositionDelta: (model) {
295+ adjustPosition = model.adjustPosition;
264296 return normalItemHeight - expandedItemHeight;
265297 },
266298 );
@@ -273,6 +305,76 @@ void main() {
273305 lastDisplayingChildModel = observeResult? .displayingChildModelList.last;
274306 expect (lastDisplayingChildModel? .index, targetIndex);
275307 expect (lastDisplayingChildModel? .trailingMarginToViewport, 0 );
308+ expect (adjustPosition, greaterThan (0 ));
309+
310+ scrollController.dispose ();
311+ });
312+
313+ testWidgets ('Keeping position with customAdjustPosition' , (tester) async {
314+ GlobalKey <ChatListViewState > key = GlobalKey ();
315+ final scrollController = ScrollController ();
316+ final observerController = ListObserverController (
317+ controller: scrollController,
318+ );
319+ ChatScrollObserverHandlePositionResultModel ? onHandlePositionResultModel;
320+ final chatScrollObserver = ChatScrollObserver (observerController)
321+ ..onHandlePositionResultCallback = (model) {
322+ onHandlePositionResultModel = model;
323+ };
324+
325+ Widget widget = ChatListView (
326+ key: key,
327+ scrollController: scrollController,
328+ observerController: observerController,
329+ chatScrollObserver: chatScrollObserver,
330+ itemBuilder: (context, index) {
331+ final dataList = key.currentState? .dataList ?? [];
332+ return Text (dataList[index]);
333+ },
334+ );
335+ await tester.pumpWidget (widget);
336+
337+ final chatListViewState = key.currentState;
338+ expect (chatListViewState, isNotNull);
339+
340+ final dataListLength = chatListViewState? .dataList.length ?? 0 ;
341+ final lastIndex = dataListLength - 1 ;
342+ observerController.jumpTo (index: lastIndex);
343+ await tester.pumpAndSettle ();
344+
345+ var result = await observerController.dispatchOnceObserve (
346+ isForce: true ,
347+ isDependObserveCallback: false ,
348+ );
349+ var lastModel = result.observeResult? .displayingChildModelList.last;
350+ expect (lastModel? .index, lastIndex);
351+ expect (lastModel? .trailingMarginToViewport, 0 );
352+ expect (onHandlePositionResultModel, isNull);
353+
354+ chatListViewState? .updateData (
355+ index: lastIndex,
356+ needSetState: true ,
357+ );
358+ await chatScrollObserver.standby (
359+ customAdjustPosition: (model) {
360+ final delta =
361+ model.newPosition.extentAfter - model.oldPosition.extentAfter;
362+ return model.adjustPosition + delta;
363+ },
364+ );
365+ await tester.pumpAndSettle ();
366+
367+ result = await observerController.dispatchOnceObserve (
368+ isForce: true ,
369+ isDependObserveCallback: false ,
370+ );
371+ lastModel = result.observeResult? .displayingChildModelList.last;
372+ expect (lastModel? .index, lastIndex);
373+ expect (lastModel? .trailingMarginToViewport, 0 );
374+ expect (
375+ onHandlePositionResultModel? .type,
376+ ChatScrollObserverHandlePositionType .keepPosition,
377+ );
276378
277379 scrollController.dispose ();
278380 });
@@ -302,6 +404,17 @@ class ChatListViewState extends State<ChatListView> {
302404 List <String > dataList =
303405 List .generate (100 , (index) => index.toString ()).toList ();
304406
407+ void updateData ({
408+ int index = 0 ,
409+ String ? appendStr,
410+ bool needSetState = true ,
411+ }) {
412+ dataList[index] += appendStr ?? 'updateData' * 10 ;
413+ if (needSetState) {
414+ setState (() {});
415+ }
416+ }
417+
305418 @override
306419 Widget build (BuildContext context) {
307420 return MaterialApp (
0 commit comments